Completed
Push — 16.1 ( 2507fe...8be54c )
by Hadi
36:07 queued 20:40
created

AppJS.extend.mail_setQuotaDisplay   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 35
rs 8.439

1 Function

Rating   Name   Duplication   Size   Complexity  
A 0 8 2
1
/* global msg */
2
3
/**
4
 * mail - static javaScript functions
5
 *
6
 * @link http://www.egroupware.org
7
 * @author EGroupware GmbH [[email protected]]
8
 * @copyright (c) 2013-2014 by EGroupware GmbH <info-AT-egroupware.org>
9
 * @package mail
10
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
11
 * @version $Id$
12
 */
13
14
/*egw:uses
15
	/api/js/jquery/jquery.base64.js;
16
*/
17
18
/**
19
 * UI for mail
20
 *
21
 * @augments AppJS
22
 */
23
app.classes.mail = AppJS.extend(
24
{
25
	appname: 'mail',
26
27
	/**
28
	 * et2 widget container
29
	 */
30
	et2: null,
31
	doStatus: null,
32
33
	mail_queuedFolders: [],
34
	mail_queuedFoldersIndex: 0,
35
36
	mail_selectedMails: [],
37
	mail_currentlyFocussed: '',
38
	mail_previewAreaActive: true, // we start with the area active
39
40
	nm_index: 'nm', // nm name of index
41
	mail_fileSelectorWindow: null,
42
	mail_isMainWindow: true,
43
44
	// Some state variables to track preview pre-loading
45
	preview_preload: {
46
		timeout: null,
47
		request: null
48
	},
49
	/**
50
	 *
51
	 */
52
	subscription_treeLastState : "",
53
54
	/**
55
	 * abbrevations for common access rights
56
	 * @array
57
	 *
58
	 */
59
	aclCommonRights:['lrs','lprs','ilprs',	'ilprsw', 'aeiklprstwx', 'custom'],
60
	/**
61
	 * Demonstrates ACL rights
62
	 * @array
63
	 *
64
	 */
65
	aclRights:['l','r','s','w','i','p','c','d','a'],
66
67
	/**
68
	 * In order to store Intervals assigned to window
69
	 * @array of setted intervals
70
	 */
71
	W_INTERVALS:[],
72
73
	/**
74
	 * Initialize javascript for this application
75
	 *
76
	 * @memberOf mail
77
	 */
78
	init: function() {
79
		this._super.apply(this,arguments);
80
		if (!this.egw.is_popup())
81
			// Turn on client side, persistent cache
82
			// egw.data system runs encapsulated below etemplate, so this must be
83
			// done before the nextmatch is created.
84
			this.egw.dataCacheRegister('mail',
85
				// Called to determine cache key
86
				this.nm_cache,
87
				// Called whenever cache is used
88
				// TODO: Change this as needed
89
				function(server_query)
90
				{
91
					// Unlock tree if using a cache, since the server won't
92
					if(!server_query) this.unlock_tree();
93
				},
94
				this
95
			);
96
	},
97
98
	/**
99
	 * Destructor
100
	 */
101
	destroy: function()
102
	{
103
		// Unbind from nm refresh
104
		if(this.et2 != null)
105
		{
106
			var nm = this.et2.getWidgetById(this.nm_index);
107
			if(nm != null)
108
			{
109
				jQuery(nm).off('refresh');
110
			}
111
		}
112
113
		// Unregister client side cache
114
		this.egw.dataCacheUnregister('mail');
115
116
		delete this.et2_obj;
117
		// call parent
118
		this._super.apply(this, arguments);
119
	},
120
121
	/**
122
	 * check and try to reinitialize et2 of module
123
	 */
124
	checkET2: function()
125
	{
126
		//this.et2 should do the same as etemplate2.getByApplication('mail')[0].widgetContainer
127
		if (!this.et2) // if not defined try this in order to recover
128
		{
129
			try
130
			{
131
				this.et2 = etemplate2.getByApplication('mail')[0].widgetContainer;
132
			}
133
			catch(e)
134
			{
135
				return false;
136
			}
137
		}
138
		return true;
139
	},
140
141
	/**
142
	 * This function is called when the etemplate2 object is loaded
143
	 * and ready.  If you must store a reference to the et2 object,
144
	 * make sure to clean it up in destroy().
145
	 *
146
	 * @param et2 etemplate2 Newly ready object
147
	 * @param {string} _name template name
148
	 */
149
	et2_ready: function(et2, _name)
150
	{
151
		// call parent; somehow this function is called more often. (twice on a display and compose) why?
152
		this._super.apply(this, arguments);
153
		this.et2_obj = et2;
154
155
		switch (_name)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
156
		{
157
			case 'mail.sieve.vacation':
158
				this.vacationFilterStatusChange();
159
				break;
160
			case 'mail.index':
161
				var self = this;
162
				jQuery('iframe#mail-index_messageIFRAME').on('load', function()
163
				{
164
					// decrypt preview body if mailvelope is available
165
					self.mailvelopeAvailable(self.mailvelopeDisplay);
166
					self.mail_prepare_print();
167
				});
168
				var nm = this.et2.getWidgetById(this.nm_index);
169
				this.mail_isMainWindow = true;
170
				this.mail_disablePreviewArea(true);
171
				//Get initial folder status
172
				this.mail_refreshFolderStatus(undefined,undefined,false);
173
174
				// Bind to nextmatch refresh to update folder status
175
				if(nm != null && (typeof jQuery._data(nm).events=='undefined'||typeof jQuery._data(nm).events.refresh == 'undefined'))
176
				{
177
					var self = this;
178
					jQuery(nm).on('refresh',function() {self.mail_refreshFolderStatus.call(self,undefined,undefined,false);});
179
				}
180
				var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
181
				if (tree_wdg)
182
				{
183
					tree_wdg.set_onopenstart(jQuery.proxy(this.openstart_tree, this));
184
					tree_wdg.set_onopenend(jQuery.proxy(this.openend_tree, this));
185
				}
186
				// Show vacation notice on load for the current profile (if not called by mail_searchtype_change())
187
				var alreadyrefreshed = this.mail_searchtype_change();
188
				if (!alreadyrefreshed) this.mail_callRefreshVacationNotice();
189
				break;
190
			case 'mail.display':
191
				var self = this;
192
				// Prepare display dialog for printing
193
				// copies iframe content to a DIV, as iframe causes
194
				// trouble for multipage printing
195
196
				jQuery('iframe#mail-display_mailDisplayBodySrc').on('load', function(e)
197
				{
198
					// encrypt body if mailvelope is available
199
					self.mailvelopeAvailable(self.mailvelopeDisplay);
200
					self.mail_prepare_print();
201
202
					// Trigger print command if the mail oppend for printing porpuse
203
					// load event fires twice in IE and the first time the content is not ready
204
					// Check if the iframe content is loaded then trigger the print command
205
					if (window.location.search.search('&print=') >= 0 && jQuery(this.contentWindow.document.body).children().length >0 )
206
					{
207
						self.mail_print();
208
					}
209
				});
210
211
				this.mail_isMainWindow = false;
212
				this.mail_display();
213
214
				// Register attachments for drag
215
				this.register_for_drag(
216
					this.et2.getArrayMgr("content").getEntry('mail_id'),
217
					this.et2.getArrayMgr("content").getEntry('mail_displayattachments')
218
				);
219
				break;
220
			case 'mail.compose':
221
				if (this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp') &&
222
					this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').checked ||
223
					this.et2.getArrayMgr('content').data.mail_plaintext &&
224
						this.et2.getArrayMgr('content').data.mail_plaintext.indexOf(this.begin_pgp_message) != -1)
225
				{
226
					this.mailvelopeAvailable(this.mailvelopeCompose);
227
				}
228
				var that = this;
229
				var textAreaWidget = this.et2.getWidgetById('mail_htmltext');
230
				this.mail_isMainWindow = false;
231
				this.compose_fieldExpander_init();
232
				this.check_sharing_filemode();
233
234
				this.subject2title();
235
236
				// Set autosaving interval to 2 minutes for compose message
237
				this.W_INTERVALS.push(window.setInterval(function (){
238
					that.saveAsDraft(null, 'autosaving');
239
				}, 120000));
240
241
				/* Control focus actions on subject to handle expanders properly.*/
242
				jQuery("#mail-compose_subject").on({
243
					focus:function(){
244
						that.compose_fieldExpander_init();
245
						that.compose_fieldExpander();
246
					}
247
				});
248
				/*Trigger compose_resizeHandler after the CKEditor is fully loaded*/
249
				jQuery('#mail-compose').on ('load',function() {
250
					if (textAreaWidget && textAreaWidget.ckeditor)
251
					{
252
						textAreaWidget.ckeditor.on('instanceReady', function(){
253
							that.compose_fieldExpander();
254
							if (egwIsMobile()) jQuery(jQuery('iframe.cke_wysiwyg_frame')[0].contentWindow.document.body).css({margin:'0'})
255
						});
256
					}
257
					else
258
					{
259
						that.compose_fieldExpander();
260
					}
261
				});
262
263
				//Resize compose after window resize to not getting scrollbar
264
				jQuery(window).on ('resize',function(e) {
265
					// Stop immediately the resize event if we are in mobile template
266
					if (egwIsMobile())
267
					{
268
						e.stopImmediatePropagation();
269
						return false;
270
					}
271
					that.compose_resizeHandler();
272
				});
273
274
				//Call drag_n_drop initialization for emails on compose
275
				this.init_dndCompose();
276
277
				// Set focus on To/body field
278
				// depending on To field value
279
				var to = this.et2.getWidgetById('to');
280
				if (to && to.get_value() && to.get_value() != '')
281
				{
282
					var content = this.et2.getArrayMgr('content').data;
283
					if (content.is_plain)
284
					{
285
						var plainText = this.et2.getWidgetById('mail_plaintext');
286
						// focus
287
						jQuery(plainText.node).focus();
288
						// get the cursor to the top of the textarea
289
						if (typeof plainText.node.setSelectionRange !='undefined') plainText.node.setSelectionRange(0,0);
290
					}
291
					else
292
					{
293
						textAreaWidget.ckeditor.on('instanceReady', function(e) {
294
							this.focus();
295
						});
296
					}
297
				}
298
				else if(to)
299
				{
300
					jQuery('input',to.node).focus();
301
				}
302
				break;
303
			case 'mail.subscribe':
304
				if (this.subscription_treeLastState != "")
305
				{
306
					var tree = this.et2.getWidgetById('foldertree');
307
					//Saved state of tree
308
					var state = jQuery.parseJSON(this.subscription_treeLastState);
309
310
					tree.input.loadJSONObject(tree._htmlencode_node(state));
311
				}
312
				break;
313
			case 'mail.folder_management':
314
				this.egw.message(this.egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'),'info','mail:folder_management');
315
				break;
316
			case 'mail.view':
317
				// we need to set mail_currentlyFocused var otherwise mail
318
				// defined actions won't work
319
				this.mail_currentlyFocussed = this.et2.mail_currentlyFocussed;
320
321
		}
322
	},
323
324
	/**
325
	 * Observer method receives update notifications from all applications
326
	 *
327
	 * App is responsible for only reacting to "messages" it is interested in!
328
	 *
329
	 * @param {string} _msg message (already translated) to show, eg. 'Entry deleted'
330
	 * @param {string} _app application name
331
	 * @param {(string|number)} _id id of entry to refresh or null
332
	 * @param {string} _type either 'update', 'edit', 'delete', 'add' or null
333
	 * - update: request just modified data from given rows.  Sorting is not considered,
334
	 *		so if the sort field is changed, the row will not be moved.
335
	 * - edit: rows changed, but sorting may be affected.  Requires full reload.
336
	 * - delete: just delete the given rows clientside (no server interaction neccessary)
337
	 * - add: requires full reload for proper sorting
338
	 * @param {string} _msg_type 'error', 'warning' or 'success' (default)
339
	 * @param {object|null} _links app => array of ids of linked entries
340
	 * or null, if not triggered on server-side, which adds that info
341
	 * @return {false|*} false to stop regular refresh, thought all observers are run
342
	 */
343
	observer: function(_msg, _app, _id, _type, _msg_type, _links)
344
	{
345
		switch(_app)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
346
		{
347
			case 'mail':
348
				if (_id === 'sieve')
349
				{
350
					var iframe = this.et2.getWidgetById('extra_iframe');
351
					if (iframe && iframe.getDOMNode())
352
					{
353
						var contentWindow = iframe.getDOMNode().contentWindow;
354
						if (contentWindow && contentWindow.app && contentWindow.app.mail)
355
						{
356
							contentWindow.app.mail.sieve_refresh();
357
						}
358
					}
359
					return false;	// mail nextmatch needs NOT to be refreshed
360
				}
361
				break;
362
363
			case 'emailadmin':	// update tree with given mail account _id and _type
364
				var tree = this.et2 ? this.et2.getWidgetById(this.nm_index+'[foldertree]') : null;
365
				if (!tree) break;
366
				var node = tree.getNode(_id);
367
				switch(_type)
368
				{
369
					case 'delete':
370
						if (node)	// we dont care for deleted accounts not shown (eg. other users)
371
						{
372
							tree.deleteItem(_id);
373
							// ToDo: blank list, if _id was active account
374
						}
375
						break
376
					case 'update':
377
					case 'edit':
378
						if (node)	// we dont care for updated accounts not shown (eg. other users)
379
						{
380
							//tree.refreshItem(_id);
381
							egw.json('mail.mail_ui.ajax_reloadNode',[_id])
382
								.sendRequest(true);
383
						}
384
						break;
385
					case 'add':
386
						tree.refreshItem(0);	// refresh root
387
						break;
388
					default: // null
389
				}
390
		}
391
		return undefined;
392
	},
393
394
	/**
395
	 * Callback function for dataFetch caching.
396
	 *
397
	 * We only cache the first chunk (50 rows), and only if search filter is not set,
398
	 * but we cache this for every combination of folder, filter & filter2.
399
	 *
400
	 * We do not cache, if we dont find selectedFolder in query_context,
401
	 * as looking it up in tree causes mails to be cached for wrong folder
402
	 * (Probably because user already clicked on an other folder)!
403
	 *
404
	 * @param {object} query_context Query information from egw.dataFetch()
405
	 * @returns {string|false} Cache key, or false to not cache
406
	 */
407
	nm_cache: function(query_context)
408
	{
409
		// Only cache first chunk of rows, if no search filter
410
		if((!query_context || !query_context.start) && query_context.count == 0 &&
411
			query_context.filters && query_context.filters.selectedFolder &&
412
			!(!query_context.filters || query_context.filters.search)
413
		)
414
		{
415
			// Make sure keys match, even if some filters are not defined
416
			// using JSON.stringfy() directly gave a crash in Safari 7.0.4
417
			return this.egw.jsonEncode({
418
				selectedFolder: query_context.filters.selectedFolder || '',
419
				cat_id: query_context.filters.cat_id || '',
420
				filter: query_context.filters.filter || '',
421
				filter2: query_context.filters.filter2 || '',
422
				sort: query_context.filters.sort
423
			});
424
		}
425
		return false;
426
	},
427
428
	/**
429
	 * mail rebuild Action menu On nm-list
430
	 *
431
	 * @param _actions
432
	 */
433
	mail_rebuildActionsOnList: function(_actions)
434
	{
435
		this.et2.getWidgetById(this.nm_index).set_actions(_actions);
436
	},
437
438
	/**
439
	 * mail_fetchCurrentlyFocussed - implementation to decide wich mail of all the selected ones is the current
440
	 *
441
	 * @param _selected array of the selected mails
442
	 * @param _reset bool - tell the function to reset the global vars used
443
	 */
444
	mail_fetchCurrentlyFocussed: function(_selected, _reset) {
445
		// reinitialize the buffer-info on selected mails
446
		if (_reset == true || typeof _selected == 'undefined')
447
		{
448
			if (_reset == true)
449
			{
450
				// Request updated data, if possible
451
				if (this.mail_currentlyFocussed!='') egw.dataRefreshUID(this.mail_currentlyFocussed);
452
				for(var k = 0; k < this.mail_selectedMails.length; k++) egw.dataRefreshUID(this.mail_selectedMails[k]);
453
				//nm.refresh(this.mail_selectedMails,'delete');
454
			}
455
			this.mail_selectedMails = [];
456
			this.mail_currentlyFocussed = '';
457
			return '';
458
		}
459
		for(var k = 0; k < _selected.length; k++)
460
		{
461
			if (jQuery.inArray(_selected[k],this.mail_selectedMails)==-1)
462
			{
463
				this.mail_currentlyFocussed = _selected[k];
464
				break;
465
			}
466
		}
467
		this.mail_selectedMails = _selected;
468
		return this.mail_currentlyFocussed;
469
	},
470
471
	/**
472
	 * mail_open - implementation of the open action
473
	 *
474
	 * @param _action
475
	 * @param _senders - the representation of the elements(s) the action is to be performed on
476
	 * @param _mode - you may pass the mode. if not given view is used (tryastext|tryashtml are supported)
477
	 */
478
	mail_open: function(_action, _senders, _mode) {
479
		if (typeof _senders == 'undefined' || _senders.length==0)
480
		{
481
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
482
			{
483
				var _senders = [];
484
				_senders.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
485
			}
486
			if ((typeof _senders == 'undefined' || _senders.length==0) && this.mail_isMainWindow)
487
			{
488
				if (this.mail_currentlyFocussed)
489
				{
490
					var _senders = [];
491
					_senders.push({id:this.mail_currentlyFocussed});
492
				}
493
			}
494
		}
495
		var _id = _senders[0].id;
496
		// reinitialize the buffer-info on selected mails
497
		if (!(_mode == 'tryastext' || _mode == 'tryashtml' || _mode == 'view' || _mode == 'print')) _mode = 'view';
498
		this.mail_selectedMails = [];
499
		this.mail_selectedMails.push(_id);
500
		this.mail_currentlyFocussed = _id;
501
502
		var dataElem = egw.dataGetUIDdata(_id);
503
		var subject = dataElem.data.subject;
504
		//alert('Open Message:'+_id+' '+subject);
505
		var h = egw().open( _id,'mail','view',_mode+'='+_id.replace(/=/g,"_")+'&mode='+_mode);
506
		egw(h).ready(function() {
507
			h.document.title = subject;
508
		});
509
		// THE FOLLOWING IS PROBABLY NOT NEEDED, AS THE UNEVITABLE PREVIEW IS HANDLING THE COUNTER ISSUE
510
		var messages = {};
511
		messages['msg'] = [_id];
512
		// When body is requested, mail is marked as read by the mail server.  Update UI to match.
513
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
514
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data['class'] != 'undefined' && (dataElem.data['class'].indexOf('unseen') >= 0 || dataElem.data['class'].indexOf('recent') >= 0))
515
		{
516
			this.mail_removeRowClass(messages,'recent');
517
			this.mail_removeRowClass(messages,'unseen');
518
			// reduce counter without server roundtrip
519
			this.mail_reduceCounterWithoutServerRoundtrip();
520
			// not needed, as an explizit read flags the message as seen anyhow
521
			//egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
522
		}
523
	},
524
525
	/**
526
	 * Open a single message in html mode
527
	 *
528
	 * @param _action
529
	 * @param _elems _elems[0].id is the row-id
530
	 */
531
	mail_openAsHtml: function(_action, _elems)
532
	{
533
		this.mail_open(_action, _elems,'tryashtml');
534
	},
535
536
	/**
537
	 * Open a single message in plain text mode
538
	 *
539
	 * @param _action
540
	 * @param _elems _elems[0].id is the row-id
541
	 */
542
	mail_openAsText: function(_action, _elems)
543
	{
544
		this.mail_open(_action, _elems,'tryastext');
545
	},
546
547
	/**
548
	 * Compose, reply or forward a message
549
	 *
550
	 * @function
551
	 * @memberOf mail
552
	 * @param _action _action.id is 'compose', 'composeasnew', 'reply', 'reply_all' or 'forward' (forward can be multiple messages)
553
	 * @param _elems _elems[0].id is the row-id
554
	 */
555
	mail_compose: function(_action, _elems)
556
	{
557
		if (typeof _elems == 'undefined' || _elems.length==0)
558
		{
559
			if (this.et2 && this.et2.getArrayMgr("content").getEntry('mail_id'))
560
			{
561
				var _elems = [];
562
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
563
			}
564
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
565
			{
566
				if (this.mail_currentlyFocussed)
567
				{
568
					var _elems = [];
569
					_elems.push({id:this.mail_currentlyFocussed});
570
				}
571
			}
572
		}
573
		// Extra info passed to egw.open()
574
		var settings = {
575
			// 'Source' Mail UID
576
			id: '',
577
			// How to pull data from the Mail IDs for the compose
578
			from: ''
579
		};
580
581
		// We only handle one for everything but forward
582
		settings.id = (typeof _elems == 'undefined'?'':_elems[0].id);
583
584
		switch(_action.id)
585
		{
586
			case 'compose':
587
				if (_elems.length == 1)
588
				{
589
					//mail_parentRefreshListRowStyle(settings.id,settings.id);
590
				}
591
				else
592
				{
593
					return this.mail_compose('forward',_elems);
594
				}
595
				break;
596
			case 'forward':
597
			case 'forwardinline':
598
			case 'forwardasattach':
599
				if (_elems.length>1||_action.id == 'forwardasattach')
600
				{
601
					settings.from = 'forward';
602
					settings.mode = 'forwardasattach';
603
					if (typeof _elems != 'undefined' && _elems.length>1)
604
					{
605
						for(var j = 1; j < _elems.length; j++)
606
						settings.id = settings.id + ',' + _elems[j].id;
607
					}
608
				}
609
				else
610
				{
611
					settings.from = 'forward';
612
					settings.mode = 'forwardinline';
613
				}
614
				break;
615
			default:
616
				// No further client side processing needed for these
617
				settings.from = _action.id;
618
		}
619
		var compose_list = egw.getOpenWindows("mail", /^compose_/);
620
		var window_name = 'compose_' + compose_list.length + '_'+ (settings.from || '') + '_' + settings.id;
621
		return egw().open('','mail','add',settings,window_name,'mail');
622
	},
623
624
	/**
625
	 * Set content into a compose window
626
	 *
627
	 * @function
628
	 * @memberOf mail
629
	 *
630
	 * @param {String} window_name The name of an open content window.
631
	 * @param {object} content
632
	 *
633
	 * @description content Data to set into the window's fields
634
	 * content.to Addresses to add to the to line
635
	 * content.cc Addresses to add to the CC line
636
	 * content.bcc Addresses to add to the BCC line
637
	 *
638
	 * @return {boolean} Success
639
	 */
640
	setCompose: function(window_name, content)
641
	{
642
		// Get window
643
		var compose = window.open('', window_name);
644
		if(!compose || compose.closed) return false;
645
646
		// Get etemplate of popup
647
		var compose_et2 = compose.etemplate2.getByApplication('mail');
648
		if(!compose_et2 || compose_et2.length != 1 || !compose_et2[0].widgetContainer)
649
		{
650
			return false;
651
		}
652
653
		// Set each field provided
654
		var success = true;
655
		var arrContent = [];
656
		for(var field in content)
657
		{
658
			try
659
			{
660
				var widget = compose_et2[0].widgetContainer.getWidgetById(field);
661
662
				// Merge array values, replace strings
663
				var value = widget.getValue() || content[field];
664
				if(jQuery.isArray(value))
665
				{
666
					if(jQuery.isArray(content[field]))
667
					{
668
						value.concat(content[field]);
669
					}
670
					else
671
					{
672
						arrContent = content[field].split(',');
673
						for (var k=0;k < arrContent.length;k++)
674
						{
675
							value.push(arrContent[k]);
676
						}
677
					}
678
				}
679
				widget.set_value(value);
680
			}
681
			catch(e)
682
			{
683
				egw.log("error", "Unable to set field %s to '%s' in window '%s'", field, content[field],window_name);
684
				success = false;
685
				continue;
0 ignored issues
show
Unused Code introduced by
This continue has no effect on the loop flow and can be removed.
Loading history...
686
			}
687
		}
688
		if (content['cc'] || content['bcc'])
689
		{
690
			this.compose_fieldExpander();
691
			this.compose_fieldExpander_init();
692
		}
693
		return success;
694
	},
695
696
	/**
697
	 * mail_disablePreviewArea - implementation of the disablePreviewArea action
698
	 *
699
	 * @param _value
700
	 */
701
	mail_disablePreviewArea: function(_value) {
702
		var splitter = this.et2.getWidgetById('mailSplitter');
703
		// return if there's no splitter we maybe in mobile mode
704
		if (typeof splitter == 'undefined' || splitter == null) return;
705
		if(splitter.isDocked())
706
		{
707
			this.mail_previewAreaActive = false;
708
		}
709
		this.et2.getWidgetById('mailPreview').set_disabled(_value);
710
		//Dock the splitter always if we are browsing with mobile
711
		if (_value==true)
712
		{
713
			if (this.mail_previewAreaActive) splitter.dock();
714
			this.mail_previewAreaActive = false;
715
		}
716
		else
717
		{
718
			if (!this.mail_previewAreaActive)
719
			{
720
				splitter.undock();
721
				window.setTimeout(function(){splitter.left.trigger('resize.et2_split.mailSplitter');},200);
722
			}
723
			this.mail_previewAreaActive = true;
724
		}
725
	},
726
727
	/**
728
	 * Create an expand on click box
729
	 *
730
	 * @param {object} _expContent an object with at least these elements
731
	 *					{build_children, data_one, data, widget, line}
732
	 *
733
	 * @param {object} _dataElem includes data of the widget which need to be expand
734
	 * @param {object} widget container of relevant template, default is this.et2
0 ignored issues
show
Documentation introduced by
The parameter widget does not exist. Did you maybe forget to remove this comment?
Loading history...
735
	 *
736
	 * @return _dataElem content of widgets
737
	 */
738
	url_email_expandOnClick: function (_expContent, _dataElem, _et2)
739
	{
740
741
		var et2 = _et2 || this.et2;
742
		for(var j = 0; j < _expContent.length; j++)
743
		{
744
			var field = _expContent[j] || [];
745
			var content = _dataElem.data[field.data] || [];
746
747
			// Add in single address, if there
748
			if(typeof field.data_one != 'undefined' && field.data != field.data_one)
749
			{
750
				if (jQuery.isArray(_dataElem.data[field.data_one]))
751
					content = content.concat(_dataElem.data[field.data_one]);
752
				else
753
					content.unshift(_dataElem.data[field.data_one]);
754
				// Unique
755
				content = content.filter(function(value, index, self) {
756
					return self.indexOf(value) === index;
757
				});
758
			}
759
760
			// Disable whole box if there are none
761
			var line = et2.getWidgetById(field.line);
762
			if(line != null) line.set_disabled(content.length == 0);
763
764
			var widget = et2.getWidgetById(field.widget);
765
			if(widget == null) continue;
766
			jQuery(widget.getDOMNode()).removeClass('visible');
767
768
			// Programatically build the child elements
769
			if(field.build_children)
770
			{
771
				// Remove any existing
772
				var children = widget.getChildren();
773
				for(var i = children.length-1; i >= 0; i--)
774
				{
775
					children[i].destroy();
776
					widget.removeChild(children[i]);
777
				}
778
				if (content.length == 1 && typeof content[0] != 'undefined' && content[0])
779
				{
780
					content = content[0].split(',');
781
				}
782
				// Add for current record
783
				var remembervalue = '';
784
				for(var i = 0; i < content.length; i++)
785
				{
786
					if (typeof content[i] != 'string' || !content[i]) continue;
787
					// if there is no @ in string, its most likely that we have a comma in the personal name part of the emailaddress
788
					if (content[i].indexOf('@')< 0)
789
					{
790
						remembervalue = content[i];
791
					}
792
					else
793
					{
794
						var value = remembervalue+(remembervalue?',':'')+content[i];
795
						var url_email_options = {
796
							id:widget.id+'_'+i,
797
							value:value,
798
							readonly:true,
799
							contact_plus:true,
800
							full_email:typeof field['full_email'] !='undefined'?field['full_email']:true
801
						};
802
						var email = et2_createWidget('url-email',url_email_options,widget);
803
						email.loadingFinished();
804
						remembervalue = '';
805
					}
806
				}
807
			}
808
			else
809
			{
810
				widget.set_value({content: content});
811
			}
812
813
			// Show or hide button, as needed
814
			line.iterateOver(function(button) {
815
				// Avoid binding to any child buttons
816
				if(button.getParent() != line) return;
0 ignored issues
show
Bug introduced by
The variable line is changed as part of the for loop for example by et2.getWidgetById(field.line) on line 761. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
817
				button.set_disabled(
818
					// Disable if only 1 address
819
					content.length <=1 || (
0 ignored issues
show
Bug introduced by
The variable content is changed as part of the for loop for example by content.0.split(",") on line 780. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
820
					// Disable if all content is visible
821
					jQuery(widget.getDOMNode()).innerWidth() >= widget.getDOMNode().scrollWidth &&
0 ignored issues
show
Bug introduced by
The variable widget is changed as part of the for loop for example by et2.getWidgetById(field.widget) on line 764. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
822
					jQuery(widget.getDOMNode()).innerHeight() >= widget.getDOMNode().scrollHeight)
823
				);
824
			},this,et2_button);
825
		}
826
827
		return _dataElem;
828
	},
829
830
	/**
831
	 * Set values for mail dispaly From,Sender,To,Cc, and Bcc
832
	 * Additionally, apply expand on click feature on thier widgets
833
	 *
834
	 */
835
	mail_display: function()
836
	{
837
		var dataElem = {data:{FROM:"",SENDER:"",TO:"",CC:"",BCC:""}};
838
		var content = this.et2.getArrayMgr('content').data;
839
		var expand_content = [
840
			{build_children: true, data_one: 'FROM', data: 'FROM', widget: 'FROM', line: 'mailDisplayHeadersFrom', full_email:false},
841
			{build_children: true,  data: 'SENDER', widget: 'SENDER', line: 'mailDisplayHeadersSender'},
842
			{build_children: true, data: 'TO', widget: 'TO', line: 'mailDisplayHeadersTo'},
843
			{build_children: true, data: 'CC', widget: 'CC', line: 'mailDisplayHeadersCc'},
844
			{build_children: true, data: 'BCC', widget:'BCC', line: 'mailDisplayHeadersBcc'}
845
		];
846
847
		if (typeof  content != 'undefiend')
848
		{
849
			dataElem.data = jQuery.extend(dataElem.data, content);
850
851
			this.url_email_expandOnClick(expand_content, dataElem);
852
			var toolbaractions = ((typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.displayToolbaractions != 'undefined')?JSON.parse(dataElem.data.displayToolbaractions):undefined);
853
			if (toolbaractions) this.et2.getWidgetById('displayToolbar').set_actions(toolbaractions);
854
		}
855
	},
856
857
	/**
858
	 * mail_preview - implementation of the preview action
859
	 *
860
	 * @param nextmatch et2_nextmatch The widget whose row was selected
861
	 * @param selected Array Selected row IDs.  May be empty if user unselected all rows.
862
	 */
863
	mail_preview: function(selected, nextmatch) {
864
		// Empty values, just in case selected is empty (user cleared selection)
865
		//dataElem.data is populated, when available with fromaddress(string),toaddress(string),additionaltoaddress(array),ccaddress (array)
866
		var dataElem = {data:{subject:"",fromaddress:"",toaddress:"",ccaddress:"",date:"",attachmentsBlock:""}};
867
		var attachmentArea = this.et2.getWidgetById('previewAttachmentArea');
868
		if(typeof selected != 'undefined' && selected.length == 1)
869
		{
870
			var _id = this.mail_fetchCurrentlyFocussed(selected);
871
			dataElem = jQuery.extend(dataElem, egw.dataGetUIDdata(_id));
872
873
			// Try to resolve winmail.data attachment
874
			if (dataElem.data && dataElem.data.attachmentsBlock[0]
875
					&& dataElem.data.attachmentsBlock[0].winmailFlag
876
					&& (dataElem.data.attachmentsBlock[0].mimetype =='application/ms-tnef' ||
877
					dataElem.data.attachmentsBlock[0].filename == "winmail.dat"))
878
			{
879
				attachmentArea.getDOMNode().classList.add('loading');
880
				this.egw.jsonq('mail.mail_ui.ajax_resolveWinmail',[_id], jQuery.proxy(function(_data){
881
					attachmentArea.getDOMNode().classList.remove('loading');
882
					if (typeof _data == 'object')
883
					{
884
						attachmentArea.set_value({content:_data});
885
886
						this.data.attachmentsBlock = _data;
887
						// Update client cache to avoid resolving winmail.dat attachment again
888
						egw.dataStoreUID(this.data.uid, this.data);
889
890
						set_prev_iframe_top();
891
					}
892
					else
893
					{
894
						console.log('Can not resolve the winmail.data!');
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
895
					}
896
				},dataElem));
897
			}
898
		}
899
900
		var $preview_iframe = jQuery('#mail-index_mailPreviewContainer');
901
902
		// Re calculate the position of preview iframe according to its visible sibilings
903
		var set_prev_iframe_top = function ()
904
		{
905
			// Need to make sure that the iframe is fullyLoad before calculation
906
			window.setTimeout(function(){
907
				var lastEl = $preview_iframe.prev().prev();
908
				// Top offset of preview iframe calculated from top level
909
				var iframeTop = $preview_iframe.offset().top;
910
				while (lastEl.css('display') === "none")
911
				{
912
					lastEl = lastEl.prev();
913
				}
914
				var offset = iframeTop - (lastEl.offset().top + lastEl.height()) || 130; // fallback to 130 px if can not calculate new top
915
916
				// preview iframe parent has position absolute, therefore need to calculate the top via position
917
				$preview_iframe.css ('top', $preview_iframe.position().top - offset + 10);
918
			}, 50);
919
		};
920
921
		if (attachmentArea && typeof _id != 'undefined' && _id !='' && typeof dataElem !== 'undefined')
0 ignored issues
show
Bug introduced by
The variable _id does not seem to be initialized in case typeof selected != "und...&& selected.length == 1 on line 868 is false. Are you sure this can never be the case?
Loading history...
922
		{
923
			// If there is content to show recalculate the size
924
			set_prev_iframe_top();
925
		}
926
		else
927
		{
928
			// Leave if we're here and there is nothing selected, too many, or no data
929
			var prevAttchArea = this.et2.getWidgetById('previewAttachmentArea');
930
			if (prevAttchArea)
931
			{
932
				prevAttchArea.set_value({content:[]});
933
				this.et2.getWidgetById('previewAttachmentArea').set_class('previewAttachmentArea noContent mail_DisplayNone');
934
				var IframeHandle = this.et2.getWidgetById('messageIFRAME');
935
				IframeHandle.set_src('about:blank');
936
				this.mail_disablePreviewArea(true);
937
			}
938
			if (!egwIsMobile())return;
939
		}
940
		// Not applied to mobile preview
941
		if (!egwIsMobile())
942
		{
943
944
			// Widget ID:data key map of widgets we can directly set from cached data
945
			var data_widgets = {
946
				'previewFromAddress':	'fromaddress',
947
				'previewDate':			'date',
948
				'previewSubject':		'subject'
949
			};
950
951
			// Set widget values from cached data
952
			for(var id in data_widgets)
953
			{
954
				var widget = this.et2.getWidgetById(id);
955
				if(widget == null) continue;
956
				widget.set_value(dataElem.data[data_widgets[id]] || "");
957
			}
958
959
			// Blank first, so we don't show previous email while loading
960
			var IframeHandle = this.et2.getWidgetById('messageIFRAME');
961
			IframeHandle.set_src('about:blank');
962
963
			// show iframe, in case we hide it from mailvelopes one and remove that
964
			jQuery(IframeHandle.getDOMNode()).show()
965
				.next(this.mailvelope_iframe_selector).remove();
966
967
			// Set up additional content that can be expanded.
968
			// We add a new URL widget for each address, so they get all the UI
969
			// TO addresses have the first one split out, not all together
970
			// list of keys:
971
			var expand_content = [
972
				{build_children: true, data_one: 'toaddress', data: 'additionaltoaddress', widget: 'additionalToAddress', line: 'mailPreviewHeadersTo'},
973
				{build_children: true, data: 'ccaddress', widget: 'additionalCCAddress', line: 'mailPreviewHeadersCC'},
974
				{build_children: false, data: 'attachmentsBlock', widget:'previewAttachmentArea', line: 'mailPreviewHeadersAttachments'}
975
			];
976
977
			// Undock the preview before running expandOnClick, because we
978
			// need to have the DOM ready for calculation.
979
			this.mail_disablePreviewArea(false);
980
981
			dataElem = this.url_email_expandOnClick(expand_content,dataElem);
982
983
			// Update the internal list of selected mails, if needed
984
			if(this.mail_selectedMails.indexOf(_id) < 0)
985
			{
986
				this.mail_selectedMails.push(_id);
987
			}
988
989
			// Request email body from server
990
			IframeHandle.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:_id}));
991
		}
992
993
		var messages = {};
994
		messages['msg'] = [_id];
995
996
		// When body is requested, mail is marked as read by the mail server.  Update UI to match.
997
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data.flags != 'undefined' && typeof dataElem.data.flags.read != 'undefined') dataElem.data.flags.read = 'read';
998
		if (typeof dataElem != 'undefined' && typeof dataElem.data != 'undefined' && typeof dataElem.data['class']  != 'undefined' && (dataElem.data['class'].indexOf('unseen') >= 0 || dataElem.data['class'].indexOf('recent') >= 0))
999
		{
1000
			this.mail_removeRowClass(messages,'recent');
1001
			this.mail_removeRowClass(messages,'unseen');
1002
			// reduce counter without server roundtrip
1003
			this.mail_reduceCounterWithoutServerRoundtrip();
1004
			if (typeof dataElem.data.dispositionnotificationto != 'undefined' && dataElem.data.dispositionnotificationto &&
1005
				typeof dataElem.data.flags.mdnsent == 'undefined' && typeof dataElem.data.flags.mdnnotsent == 'undefined')
1006
			{
1007
				var buttons = [
1008
					{text: this.egw.lang("Yes"), id: "mdnsent"},
1009
					{text: this.egw.lang("No"), id:"mdnnotsent"}
1010
				];
1011
				et2_dialog.show_dialog(function(_button_id, _value) {
1012
					switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1013
					{
1014
						case "mdnsent":
1015
							egw.jsonq('mail.mail_ui.ajax_sendMDN',[messages]);
1016
							egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnsent', messages, true]);
1017
							return;
1018
						case "mdnnotsent":
1019
							egw.jsonq('mail.mail_ui.ajax_flagMessages',['mdnnotsent', messages, true]);
1020
					}
1021
				},
1022
				this.egw.lang("The message sender has requested a response to indicate that you have read this message. Would you like to send a receipt?"),
1023
				this.egw.lang("Confirm"),
1024
				messages, buttons);
1025
			}
1026
			egw.jsonq('mail.mail_ui.ajax_flagMessages',['read', messages, false]);
1027
		}
1028
	},
1029
1030
	/**
1031
	 * If a preview header is partially hidden, this is the handler for clicking the
1032
	 * expand button that shows all the content for that header.
1033
	 * The button must be directly after the widget to be expanded in the template.
1034
	 * The widget to be expended is set in the event data.
1035
	 *
1036
	 * requires: mainWindow, one mail selected for preview
1037
	 *
1038
	 * @param {jQuery event} event
1039
	 * @param {Object} widget
1040
	 * @param {DOMNode} button
1041
	 */
1042
	showAllHeader: function(event,widget,button) {
1043
		// Show list as a list
1044
		var list = jQuery(button).prev();
1045
	/*	if (list.length <= 0)
1046
		{
1047
			list = jQuery(button.target).prev();
1048
		}*/
1049
1050
		list.toggleClass('visible');
1051
1052
		// Revert if user clicks elsewhere
1053
		jQuery('body').one('click', list, function(ev) {
1054
			ev.data.removeClass('visible');
1055
		});
1056
	},
1057
1058
	mail_setMailBody: function(content) {
1059
		var IframeHandle = this.et2.getWidgetById('messageIFRAME');
1060
		IframeHandle.set_value('');
1061
	},
1062
1063
	/**
1064
	 * mail_refreshFolderStatus, function to call to read the counters of a folder and apply them
1065
	 *
1066
	 * @param {stirng} _nodeID
1067
	 * @param {string} mode
1068
	 * @param {boolean} _refreshGridArea
1069
	 * @param {boolean} _refreshQuotaDisplay
1070
	 *
1071
	 */
1072
	mail_refreshFolderStatus: function(_nodeID,mode,_refreshGridArea,_refreshQuotaDisplay) {
1073
		if (typeof _nodeID != 'undefined' && typeof _nodeID[_nodeID] != 'undefined' && _nodeID[_nodeID])
1074
		{
1075
			_refreshGridArea = _nodeID[_refreshGridArea];
1076
			mode = _nodeID[mode];
1077
			_nodeID = _nodeID[_nodeID];
1078
		}
1079
		var nodeToRefresh = 0;
1080
		var mode2use = "none";
1081
		if (typeof _refreshGridArea == 'undefined') _refreshGridArea=true;
1082
		if (typeof _refreshQuotaDisplay == 'undefined') _refreshQuotaDisplay=true;
1083
		if (_nodeID) nodeToRefresh = _nodeID;
1084
		if (mode) {
1085
			if (mode == "forced") {mode2use = mode;}
1086
		}
1087
		try
1088
		{
1089
			var tree_wdg = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1090
1091
			var activeFolders = tree_wdg.getTreeNodeOpenItems(nodeToRefresh,mode2use);
1092
			//alert(activeFolders.join('#,#'));
1093
			this.mail_queueRefreshFolderList((mode=='thisfolderonly'&&nodeToRefresh?[_nodeID]:activeFolders));
1094
			if (_refreshGridArea)
1095
			{
1096
				// maybe to use the mode forced as trigger for grid reload and using the grids own autorefresh
1097
				// would solve the refresh issue more accurately
1098
				//if (mode == "forced") this.mail_refreshMessageGrid();
1099
				this.mail_refreshMessageGrid();
1100
			}
1101
			if (_refreshQuotaDisplay)
1102
			{
1103
				this.mail_refreshQuotaDisplay();
1104
			}
1105
			//the two lines below are not working yet.
1106
			//var no =tree_wdg.getSelectedNode();
1107
			//tree_wdg.focusItem(no.id);
1108
		} catch(e) { } // ignore the error; maybe the template is not loaded yet
1109
	},
1110
1111
	/**
1112
	 * mail_refreshQuotaDisplay, function to call to read the quota for the active server
1113
	 *
1114
	 * @param {object} _server
1115
	 *
1116
	 */
1117
	mail_refreshQuotaDisplay: function(_server)
1118
	{
1119
		egw.json('mail.mail_ui.ajax_refreshQuotaDisplay',[_server])
1120
			.sendRequest(true);
1121
	},
1122
1123
	/**
1124
	 * mail_setQuotaDisplay, function to call to read the quota for the active server
1125
	 *
1126
	 * @param {object} _data
1127
	 *
1128
	 */
1129
	mail_setQuotaDisplay: function(_data)
1130
	{
1131
		if (!this.et2 && !this.checkET2()) return;
1132
1133
		var quotabox = this.et2.getWidgetById(this.nm_index+'[quotainpercent]');
1134
1135
		// Check to make sure it's there
1136
		if(quotabox)
1137
		{
1138
			//try to set it via set_value and set label
1139
			quotabox.set_class(_data.data.quotaclass);
1140
			quotabox.set_value(_data.data.quotainpercent);
1141
			quotabox.set_label(_data.data.quota);
1142
			if (_data.data.quotawarning)
1143
			{
1144
				var self = this;
1145
				var buttons = [
1146
					{text: this.egw.lang("Empty Trash and Junk"), id: "cleanup", class: "ui-priority-primary", default: true, image:"delete"},
1147
					{text: this.egw.lang("Cancel"), id:"cancel"}
1148
				];
1149
				var server = [{iface:{id: _data.data.profileid+'::'}}];
1150
				et2_dialog.show_dialog(function(_button_id) {
1151
					if (_button_id == "cleanup")
1152
					{
1153
						self.mail_emptySpam (null, server);
1154
						self.mail_emptyTrash (null, server);
1155
					}
1156
					return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
1157
				},
1158
				this.egw.lang("Your mail quota is %1% full, you may not be able to send/receive further emails.\n Although cleaning up emails in trash or junk folder might help you to get some free space back.\n If that didn't help, please ask administrator for more quota.", _data.data.quotainpercent),
1159
				this.egw.lang("Mail cleanup"),
1160
				'', buttons, et2_dialog.WARNING_MESSAGE);
1161
			}
1162
		}
1163
	},
1164
1165
	/**
1166
	 * mail_callRefreshVacationNotice, function to call the serverside function to refresh the vacationnotice for the active server
1167
	 *
1168
	 * @param {object} _server
1169
	 *
1170
	 */
1171
	mail_callRefreshVacationNotice: function(_server)
1172
	{
1173
		egw.jsonq('mail_ui::ajax_refreshVacationNotice',[_server]);
1174
	},
1175
	/**
1176
	 * Make sure attachments have all needed data, so they can be found for
1177
	 * HTML5 native dragging
1178
	 *
1179
	 * @param {string} mail_id Mail UID
1180
	 * @param {array} attachments Attachment information.
1181
	 */
1182
	register_for_drag: function(mail_id, attachments)
1183
	{
1184
		// Put required info in global store
1185
		var data = {};
1186
		if (!attachments) return;
1187
		for (var i = 0; i < attachments.length; i++)
1188
		{
1189
			var data = attachments[i] || {};
1190
			if(!data.filename || !data.type) continue;
1191
1192
			// Add required info
1193
			data.mime = data.type;
1194
			data.download_url = egw.link('/index.php', {
1195
				menuaction: 'mail.mail_ui.getAttachment',
1196
				id: mail_id,
1197
				part: data.partID,
1198
				is_winmail: data.winmailFlag
1199
			});
1200
			data.name = data.filename;
1201
		}
1202
	},
1203
1204
	/**
1205
	 * Display helper for dragging attachments
1206
	 *
1207
	 * @param {egwAction} _action
1208
	 * @param {egwActionElement[]} _elems
1209
	 * @returns {DOMNode}
1210
	 */
1211
	drag_attachment: function(_action, _elems)
1212
	{
1213
		var div = jQuery(document.createElement("div"))
1214
			.css({
1215
				position: 'absolute',
1216
				top: '0px',
1217
				left: '0px',
1218
				width: '300px'
1219
			});
1220
1221
		var data = _elems[0].data || {};
1222
1223
		var text = jQuery(document.createElement('div')).css({left: '30px', position: 'absolute'});
1224
		// add filename or number of files for multiple files
1225
		text.text(_elems.length > 1 ? _elems.length+' '+this.egw.lang('files') : data.name || '');
1226
		div.append(text);
1227
1228
		// Add notice of Ctrl key, if supported
1229
		if(window.FileReader && 'draggable' in document.createElement('span') &&
1230
			navigator && navigator.userAgent.indexOf('Chrome') >= 0)
1231
		{
1232
			var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ? 'Ctrl' : 'Command';
1233
			text.append('<br />' + this.egw.lang('Hold %1 to drag files to your computer',key));
1234
		}
1235
		return div;
1236
	},
1237
1238
	/**
1239
	 * mail_refreshVacationNotice, function to call with appropriate data to refresh the vacationnotice for the active server
1240
	 *
1241
	 * @param {object} _data
1242
	 *
1243
	 */
1244
	mail_refreshVacationNotice: function(_data)
1245
	{
1246
		if (!this.et2 && !this.checkET2()) return;
1247
		if (_data == null)
1248
		{
1249
			this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value('');
1250
			this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value('');
1251
		}
1252
		else
1253
		{
1254
			this.et2.getWidgetById(this.nm_index+'[vacationnotice]').set_value(_data.vacationnotice);
1255
			this.et2.getWidgetById(this.nm_index+'[vacationrange]').set_value(_data.vacationrange);
1256
		}
1257
	},
1258
1259
	/**
1260
	 * Enable or disable the date filter
1261
	 *
1262
	 * If the searchtype (cat_id) is set to something that needs dates, we enable the
1263
	 * header_right template.  Otherwise, it is disabled.
1264
	 */
1265
	mail_searchtype_change: function()
1266
	{
1267
		var filter = this.et2.getWidgetById('cat_id');
1268
		var nm = this.et2.getWidgetById(this.nm_index);
1269
		var dates = this.et2.getWidgetById('mail.index.datefilter');
1270
		if(nm && filter)
1271
		{
1272
			switch(filter.getValue())
1273
			{
1274
				case 'bydate':
1275
1276
					if (filter && dates)
1277
					{
1278
						dates.set_disabled(false);
1279
						if (this.et2.getWidgetById('startdate')) jQuery(this.et2.getWidgetById('startdate').getDOMNode()).find('input').focus();
1280
					}
1281
					this.mail_callRefreshVacationNotice();
1282
					return true;
1283
				default:
1284
					if (dates)
1285
					{
1286
						dates.set_disabled(true);
1287
					}
1288
					this.mail_callRefreshVacationNotice();
1289
					return true;
1290
			}
1291
		}
1292
		return false;
1293
	},
1294
1295
	/**
1296
	 * mail_refreshFilter2Options, function to call with appropriate data to refresh the filter2 options for the active server
1297
	 *
1298
	 * @param {object} _data
1299
	 *
1300
	 */
1301
	mail_refreshFilter2Options: function(_data)
1302
	{
1303
		//alert('mail_refreshFilter2Options');
1304
		if (_data == null) return;
1305
		if (!this.et2 && !this.checkET2()) return;
1306
1307
		var filter2 = this.et2.getWidgetById('filter2');
1308
		var current = filter2.value;
1309
		var currentexists=false;
1310
		for (var k in _data)
1311
		{
1312
			if (k==current) currentexists=true;
1313
		}
1314
		if (!currentexists) filter2.set_value('');
1315
		filter2.set_select_options(_data);
1316
	},
1317
1318
	/**
1319
	 * mail_refreshFilterOptions, function to call with appropriate data to refresh the filter options for the active server
1320
	 *
1321
	 * @param {object} _data
1322
	 *
1323
	 */
1324
	mail_refreshFilterOptions: function(_data)
1325
	{
1326
		//alert('mail_refreshFilterOptions');
1327
		if (_data == null) return;
1328
		if (!this.et2 && !this.checkET2()) return;
1329
1330
		var filter = this.et2.getWidgetById('filter');
1331
		var current = filter.value;
1332
		var currentexists=false;
1333
		for (var k in _data)
1334
		{
1335
			if (k==current) currentexists=true;
1336
		}
1337
		if (!currentexists) filter.set_value('any');
1338
		filter.set_select_options(_data);
1339
1340
	},
1341
1342
	/**
1343
	 * mail_refreshCatIdOptions, function to call with appropriate data to refresh the filter options for the active server
1344
	 *
1345
	 * @param {object} _data
1346
	 *
1347
	 */
1348
	mail_refreshCatIdOptions: function(_data)
1349
	{
1350
		//alert('mail_refreshCatIdOptions');
1351
		if (_data == null) return;
1352
		if (!this.et2 && !this.checkET2()) return;
1353
1354
		var filter = this.et2.getWidgetById('cat_id');
1355
		var current = filter.value;
1356
		var currentexists=false;
1357
		for (var k in _data)
1358
		{
1359
			if (k==current) currentexists=true;
1360
		}
1361
		if (!currentexists) filter.set_value('quick');
1362
		filter.set_select_options(_data);
1363
1364
	},
1365
1366
	/**
1367
	 * Queues a refreshFolderList request for 500ms. Actually this will just execute the
1368
	 * code after the calling script has finished.
1369
	 *
1370
	 * @param {array} _folders description
1371
	 */
1372
	mail_queueRefreshFolderList: function(_folders)
1373
	{
1374
		var self = this;
1375
		// as jsonq is too fast wrap it to be delayed a bit, to ensure the folder actions
1376
		// are executed last of the queue
1377
		window.setTimeout(function() {
1378
			egw.jsonq('mail.mail_ui.ajax_setFolderStatus',[_folders], function (){self.unlock_tree();});
1379
		}, 500);
1380
	},
1381
1382
	/**
1383
	 * mail_CheckFolderNoSelect - implementation of the mail_CheckFolderNoSelect action to control right click options on the tree
1384
	 *
1385
	 * @param {object} action
1386
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1387
	 * @param {object} _currentNode
1388
	 */
1389
	mail_CheckFolderNoSelect: function(action,_senders,_currentNode) {
1390
1391
		// Abort if user selected an un-selectable node
1392
		// Use image over anything else because...?
1393
		var ftree, node;
1394
		ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1395
		if (ftree)
1396
		{
1397
			node = ftree.getNode(_senders[0].id);
1398
		}
1399
1400
		if (node && node.im0.indexOf('NoSelect') !== -1)
1401
		{
1402
			//ftree.reSelectItem(_previous);
1403
			return false;
1404
		}
1405
1406
		return true;
1407
	},
1408
1409
	/**
1410
	 * Check if SpamFolder is enabled on that account
1411
	 *
1412
	 * SpamFolder enabled is stored as data { spamfolder: true/false } on account node.
1413
	 *
1414
	 * @param {object} _action
1415
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1416
	 * @param {object} _currentNode
1417
	 */
1418
	spamfolder_enabled: function(_action,_senders,_currentNode)
1419
	{
1420
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1421
		var acc_id = _senders[0].id.split('::')[0];
1422
		var node = ftree ? ftree.getNode(acc_id) : null;
1423
1424
		return node && node.data && node.data.spamfolder;
1425
	},
1426
1427
1428
	/**
1429
	 * Check if archiveFolder is enabled on that account
1430
	 *
1431
	 * ArchiveFolder enabled is stored as data { archivefolder: true/false } on account node.
1432
	 *
1433
	 * @param {object} _action
1434
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1435
	 * @param {object} _currentNode
1436
	 */
1437
	archivefolder_enabled: function(_action,_senders,_currentNode)
1438
	{
1439
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1440
		var acc_id = _senders[0].id.split('::')[2]; // this is operating on mails
1441
		var node = ftree ? ftree.getNode(acc_id) : null;
1442
1443
		return node && node.data && node.data.archivefolder;
1444
	},
1445
1446
	/**
1447
	 * Check if Sieve is enabled on that account
1448
	 *
1449
	 * Sieve enabled is stored as data { sieve: true/false } on account node.
1450
	 *
1451
	 * @param {object} _action
1452
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1453
	 * @param {object} _currentNode
1454
	 */
1455
	sieve_enabled: function(_action,_senders,_currentNode)
1456
	{
1457
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1458
		var acc_id = _senders[0].id.split('::')[0];
1459
		var node = ftree ? ftree.getNode(acc_id) : null;
1460
1461
		return node && node.data && node.data.sieve;
1462
	},
1463
1464
	/**
1465
	 * Check if ACL is enabled on that account
1466
	 *
1467
	 * ACL enabled is stored as data { acl: true/false } on INBOX node.
1468
	 * We also need to check if folder is marked as no-select!
1469
	 *
1470
	 * @param {object} _action
1471
	 * @param {object} _senders the representation of the tree leaf to be manipulated
1472
	 * @param {object} _currentNode
1473
	 */
1474
	acl_enabled: function(_action,_senders,_currentNode)
1475
	{
1476
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1477
		var inbox = _senders[0].id.split('::')[0]+'::INBOX';
1478
		var node = ftree ? ftree.getNode(inbox) : null;
1479
1480
		return node && node.data.acl && this.mail_CheckFolderNoSelect(_action,_senders,_currentNode);
1481
	},
1482
1483
	/**
1484
	 * mail_setFolderStatus, function to set the status for the visible folders
1485
	 *
1486
	 * @param {array} _status
1487
	 */
1488
	mail_setFolderStatus: function(_status) {
1489
		if (!this.et2 && !this.checkET2()) return;
1490
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1491
		for (var i in _status) {
1492
			ftree.setLabel(i,_status[i]);
1493
			// display folder-name bold for unseen mails
1494
			ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
1495
			//alert(i +'->'+_status[i]);
1496
		}
1497
	},
1498
1499
	/**
1500
	 * mail_setLeaf, function to set the id and description for the folder given by status key
1501
	 * @param {array} _status status array with the required data (new id, desc, old desc)
1502
	 *		key is the original id of the leaf to change
1503
	 *		multiple sets can be passed to mail_setLeaf
1504
	 */
1505
	mail_setLeaf: function(_status) {
1506
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1507
		var selectedNode = ftree.getSelectedNode();
1508
		for (var i in _status)
1509
		{
1510
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1511
			if (typeof _status[i]['olddesc'] !== 'undefined' && _status[i]['olddesc'] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Renamed Folder %1 to %2",_status[i]['olddesc'],_status[i]['desc']));
1512
			ftree.renameItem(i,_status[i]['id'],_status[i]['desc']);
1513
			ftree.setStyle(i, 'font-weight: '+(_status[i]['desc'].match(this._unseen_regexp) ? 'bold' : 'normal'));
1514
			//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
1515
			if (_status[i]['id']==selectedNode.id)
1516
			{
1517
				var nm = this.et2.getWidgetById(this.nm_index);
1518
				nm.activeFilters["selectedFolder"] = _status[i]['id'];
1519
				nm.applyFilters();
1520
			}
1521
		}
1522
	},
1523
1524
	/**
1525
	 * mail_removeLeaf, function to remove the leaf represented by the given ID
1526
	 * @param {array} _status status array with the required data (KEY id, VALUE desc)
1527
	 *		key is the id of the leaf to delete
1528
	 *		multiple sets can be passed to mail_deleteLeaf
1529
	 */
1530
	mail_removeLeaf: function(_status) {
1531
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1532
		var selectedNode = ftree.getSelectedNode();
1533
		for (var i in _status)
1534
		{
1535
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1536
			if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#') this.egw.message(this.egw.lang("Removed Folder %1 ",_status[i]));
1537
			ftree.deleteItem(i,(selectedNode.id==i));
1538
			var selectedNodeAfter = ftree.getSelectedNode();
1539
			//alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']);
1540
			if (selectedNodeAfter.id!=selectedNode.id && selectedNode.id==i)
1541
			{
1542
				var nm = this.et2.getWidgetById(this.nm_index);
1543
				nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
1544
				nm.applyFilters();
1545
			}
1546
		}
1547
	},
1548
1549
	/**
1550
	 * mail_reloadNode, function to reload the leaf represented by the given ID
1551
	 * @param {Object.<string,string>|Object.<string,Object}}  _status
1552
	 *		Object with the required data (KEY id, VALUE desc), or ID => {new data}
1553
	 */
1554
	mail_reloadNode: function(_status) {
1555
		var ftree = this.et2?this.et2.getWidgetById(this.nm_index+'[foldertree]'):null;
1556
		if (!ftree) return;
1557
		var selectedNode = ftree.getSelectedNode();
1558
		for (var i in _status)
1559
		{
1560
			// if olddesc is undefined or #skip# then skip the message, as we process subfolders
1561
			if (typeof _status[i] !== 'undefined' && _status[i] !== '#skip-user-interaction-message#')
1562
			{
1563
				if (typeof _status[i].parent !== 'undefined')
1564
				{
1565
					this.egw.message(this.egw.lang("Reloaded Folder %1",typeof _status[i] == "string" ? _status[i].replace(this._unseen_regexp, '') : _status[i].text.replace(this._unseen_regexp, '')));
1566
				} else {
1567
					this.egw.message(this.egw.lang("Reloaded Account %1",typeof _status[i] == "string" ? _status[i].replace(this._unseen_regexp, '') : _status[i].text.replace(this._unseen_regexp, '')));
1568
				}
1569
			}
1570
			ftree.refreshItem(i,typeof _status[i] == "object" ? _status[i] : null);
1571
			if (typeof _status[i] == "string") ftree.setStyle(i, 'font-weight: '+(_status[i].match(this._unseen_regexp) ? 'bold' : 'normal'));
1572
		}
1573
1574
		var selectedNodeAfter = ftree.getSelectedNode();
1575
1576
		// If selected folder changed, refresh nextmatch
1577
		if (selectedNodeAfter != null && selectedNodeAfter.id!=selectedNode.id)
1578
		{
1579
			var nm = this.et2.getWidgetById(this.nm_index);
1580
			nm.activeFilters["selectedFolder"] = selectedNodeAfter.id;
1581
			nm.applyFilters();
1582
		}
1583
	},
1584
1585
	/**
1586
	 * mail_refreshMessageGrid, function to call to reread ofthe current folder
1587
	 *
1588
	 * @param {boolean} _isPopup
1589
	 */
1590
	mail_refreshMessageGrid: function(_isPopup, _refreshVacationNotice) {
1591
		if (typeof _isPopup == 'undefined') _isPopup = false;
1592
		if (typeof _refreshVacationNotice == 'undefined') _refreshVacationNotice = false;
1593
		var nm;
1594
		if (_isPopup && !this.mail_isMainWindow)
1595
		{
1596
			nm = window.opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index);
1597
		}
1598
		else
1599
		{
1600
			nm = this.et2.getWidgetById(this.nm_index);
1601
		}
1602
		var dates = this.et2.getWidgetById('mail.index.datefilter');
1603
		var filter = this.et2.getWidgetById('cat_id');
1604
		if(nm && filter)
1605
		{
1606
			nm.activeFilters["startdate"]=null;
1607
			nm.activeFilters["enddate"]=null;
1608
			switch(filter.getValue())
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
1609
			{
1610
				case 'bydate':
1611
1612
					if (filter && dates)
1613
					{
1614
						if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) nm.activeFilters["startdate"] = this.et2.getWidgetById('startdate').date;
1615
						if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) nm.activeFilters["enddate"] = this.et2.getWidgetById('enddate').date;
1616
					}
1617
			}
1618
		}
1619
		nm.applyFilters(); // this should refresh the active folder
1620
		if (_refreshVacationNotice) this.mail_callRefreshVacationNotice();
1621
	},
1622
1623
	/**
1624
	 * mail_getMsg - gets the current Message
1625
	 * @return string
1626
	 */
1627
	mail_getMsg: function()
1628
	{
1629
		var msg_wdg = this.et2.getWidgetById('msg');
1630
		if (msg_wdg)
1631
		{
1632
			return msg_wdg.valueOf().htmlNode[0].innerHTML;
1633
		}
1634
		return "";
1635
	},
1636
1637
	/**
1638
	 * mail_setMsg - sets a Message, with the msg container, and controls if the container is enabled/disabled
1639
	 * @param {string} myMsg - the message
1640
	 */
1641
	mail_setMsg: function(myMsg)
1642
	{
1643
		var msg_wdg = this.et2.getWidgetById('msg');
1644
		if (msg_wdg)
1645
		{
1646
			msg_wdg.set_value(myMsg);
1647
			msg_wdg.set_disabled(myMsg.trim().length==0);
1648
		}
1649
	},
1650
1651
	/**
1652
	 * Delete mails
1653
	 * takes in all arguments
1654
	 * @param _action
1655
	 * @param _elems
1656
	 */
1657
	mail_delete: function(_action,_elems)
1658
	{
1659
		this.mail_checkAllSelected(_action,_elems,null,true);
1660
	},
1661
1662
	/**
1663
	 * call Delete mails
1664
	 * takes in all arguments
1665
	 * @param {object} _action
1666
	 * @param {array} _elems
1667
	 * @param {boolean} _allMessagesChecked
1668
	 */
1669
	mail_callDelete: function(_action,_elems,_allMessagesChecked)
1670
	{
1671
		var calledFromPopup = false;
1672
		if (typeof _allMessagesChecked == 'undefined') _allMessagesChecked=false;
1673
		if (typeof _elems == 'undefined' || _elems.length==0)
1674
		{
1675
			calledFromPopup = true;
1676
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
1677
			{
1678
				var _elems = [];
1679
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
1680
			}
1681
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
1682
			{
1683
				if (this.mail_currentlyFocussed)
1684
				{
1685
					var _elems = [];
1686
					_elems.push({id:this.mail_currentlyFocussed});
1687
				}
1688
			}
1689
		}
1690
		var msg = this.mail_getFormData(_elems);
1691
		msg['all'] = _allMessagesChecked;
1692
		if (msg['all']=='cancel') return false;
1693
		if (msg['all']) msg['activeFilters'] = this.mail_getActiveFilters(_action);
1694
		//alert(_action.id+','+ msg);
1695
		if (!calledFromPopup) this.mail_setRowClass(_elems,'deleted');
1696
		this.mail_deleteMessages(msg,'no',calledFromPopup);
1697
		if (calledFromPopup && this.mail_isMainWindow==false)
1698
		{
1699
			egw(window).close();
1700
		}
1701
		else if (typeof this.et2_view!='undefined' && typeof this.et2_view.close == 'function')
1702
		{
1703
			this.et2_view.close();
1704
		}
1705
	},
1706
1707
	/**
1708
	 * function to find (and reduce) unseen count from folder-name
1709
	 */
1710
	mail_reduceCounterWithoutServerRoundtrip: function()
1711
	{
1712
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1713
		var _foldernode = ftree.getSelectedNode();
1714
		var counter = _foldernode.label.match(this._unseen_regexp);
1715
		var icounter = 0;
1716
		if ( counter ) icounter = parseInt(counter[0].replace(' (','').replace(')',''));
1717
		if (icounter>0)
1718
		{
1719
			var newcounter = icounter-1;
1720
			if (newcounter>0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')',' ('+String(newcounter)+')');
1721
			if (newcounter==0) _foldernode.label = _foldernode.label.replace(' ('+String(icounter)+')','');
1722
			ftree.setLabel(_foldernode.id,_foldernode.label);
1723
		}
1724
	},
1725
1726
	/**
1727
	 * Regular expression to find (and remove) unseen count from folder-name
1728
	 */
1729
	_unseen_regexp: / \([0-9]+\)$/,
1730
1731
	/**
1732
	 * mail_splitRowId
1733
	 *
1734
	 * @param {string} _rowID
1735
	 *
1736
	 */
1737
	mail_splitRowId: function(_rowID)
1738
	{
1739
		var res = _rowID.split('::');
1740
		// as a rowID is perceeded by app::, should be mail!
1741
		if (res.length==4 && !isNaN(parseInt(res[0])))
1742
		{
1743
			// we have an own created rowID; prepend app=mail
1744
			res.unshift('mail');
1745
		}
1746
		return res;
1747
	},
1748
1749
	/**
1750
	 * Delete mails - actually calls the backend function for deletion
1751
	 * takes in all arguments
1752
	 * @param {string} _msg - message list
1753
	 * @param {object} _action - optional action
1754
	 * @param {object} _calledFromPopup
1755
	 */
1756
	mail_deleteMessages: function(_msg,_action,_calledFromPopup)
1757
	{
1758
		var message, ftree, _foldernode, displayname;
1759
		ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
1760
		if (ftree)
1761
		{
1762
			_foldernode = ftree.getSelectedNode();
1763
1764
			displayname = _foldernode.label.replace(this._unseen_regexp, '');
1765
		}
1766
		else
1767
		{
1768
			message = this.mail_splitRowId(_msg['msg'][0]);
1769
			if (message[3]) _foldernode = displayname = jQuery.base64Decode(message[3]);
1770
		}
1771
1772
		// Tell server
1773
		egw.json('mail.mail_ui.ajax_deleteMessages',[_msg,(typeof _action == 'undefined'?'no':_action)])
1774
			.sendRequest(true);
1775
1776
		if (_msg['all']) this.egw.refresh(this.egw.lang("deleted %1 messages in %2",(_msg['all']?egw.lang('all'):_msg['msg'].length),(displayname?displayname:egw.lang('current folder'))),'mail');//,ids,'delete');
1777
		this.egw.message(this.egw.lang("deleted %1 messages in %2",(_msg['all']?egw.lang('all'):_msg['msg'].length),(displayname?displayname:egw.lang('current Folder'))));
1778
	},
1779
1780
	/**
1781
	 * Delete mails show result - called from the backend function for display of deletionmessages
1782
	 * takes in all arguments
1783
	 * @param _msg - message list
1784
	 */
1785
	mail_deleteMessagesShowResult: function(_msg)
1786
	{
1787
		// Update list
1788
		var ids = [];
1789
		for (var i = 0; i < _msg['msg'].length; i++)
1790
		{
1791
			ids.push(_msg['msg'][i].replace(/mail::/,''));
1792
		}
1793
		//this.egw.message(_msg['egw_message']);
1794
		if (_msg['all'])
1795
		{
1796
			this.egw.refresh(_msg['egw_message'],'mail');
1797
		}
1798
		else
1799
		{
1800
			this.egw.refresh(_msg['egw_message'],'mail',ids,'delete');
1801
1802
			// Nextmatch automatically selects the next row and calls preview.
1803
			// Unselect it and thanks to the timeout selectionMgr uses, preview
1804
			// will close when the selection callback fires.
1805
			this.et2.getWidgetById(this.nm_index).controller._selectionMgr.resetSelection();
1806
		}
1807
	},
1808
1809
	/**
1810
	 * retry to Delete mails
1811
	 * @param responseObject ->
1812
	 * 	 reason - reason to report
1813
	 * 	 messageList
1814
	 */
1815
	mail_retryForcedDelete: function(responseObject)
1816
	{
1817
		var reason = responseObject['response'];
1818
		var messageList = responseObject['messageList'];
1819
		if (confirm(reason))
1820
		{
1821
			this.mail_deleteMessages(messageList,'remove_immediately');
1822
		}
1823
		else
1824
		{
1825
			this.egw.message(this.egw.lang('canceled deletion due to userinteraction'));
1826
			this.mail_removeRowClass(messageList,'deleted');
1827
		}
1828
		this.mail_refreshMessageGrid();
1829
		this.mail_preview();
1830
	},
1831
1832
	/**
1833
	 * UnDelete mailMessages
1834
	 *
1835
	 * @param _messageList
1836
	 */
1837
	mail_undeleteMessages: function(_messageList) {
1838
	// setting class of row, the old style
1839
	},
1840
1841
	/**
1842
	 * mail_emptySpam
1843
	 *
1844
	 * @param {object} action
1845
	 * @param {object} _senders
1846
	 */
1847
	mail_emptySpam: function(action,_senders) {
1848
		var server = _senders[0].iface.id.split('::');
1849
		var activeFilters = this.mail_getActiveFilters();
1850
		var self = this;
1851
1852
		this.egw.message(this.egw.lang('empty junk'));
1853
		egw.json('mail.mail_ui.ajax_emptySpam',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
1854
			.sendRequest(true);
1855
1856
		// Directly delete any trash cache for selected server
1857
		if(window.localStorage)
1858
		{
1859
			for(var i = 0; i < window.localStorage.length; i++)
1860
			{
1861
				var key = window.localStorage.key(i);
1862
1863
				// Find directly by what the key would look like
1864
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
1865
					key.toLowerCase().indexOf(egw.lang('junk').toLowerCase()) > 0)
1866
				{
1867
					window.localStorage.removeItem(key);
1868
				}
1869
			}
1870
		}
1871
	},
1872
1873
	/**
1874
	 * mail_emptyTrash
1875
	 *
1876
	 * @param {object} action
1877
	 * @param {object} _senders
1878
	 */
1879
	mail_emptyTrash: function(action,_senders) {
1880
		var server = _senders[0].iface.id.split('::');
1881
		var activeFilters = this.mail_getActiveFilters();
1882
		var self = this;
1883
1884
		this.egw.message(this.egw.lang('empty trash'));
1885
		egw.json('mail.mail_ui.ajax_emptyTrash',[server[0], activeFilters['selectedFolder']? activeFilters['selectedFolder']:null],function(){self.unlock_tree();})
1886
			.sendRequest(true);
1887
1888
		// Directly delete any trash cache for selected server
1889
		if(window.localStorage)
1890
		{
1891
			for(var i = 0; i < window.localStorage.length; i++)
1892
			{
1893
				var key = window.localStorage.key(i);
1894
1895
				// Find directly by what the key would look like
1896
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+server[0]+'::') == 0 &&
1897
					key.toLowerCase().indexOf(egw.lang('trash').toLowerCase()) > 0)
1898
				{
1899
					window.localStorage.removeItem(key);
1900
				}
1901
			}
1902
		}
1903
	},
1904
1905
	/**
1906
	 * mail_compressFolder
1907
	 *
1908
	 * @param {object} action
1909
	 * @param {object} _senders
1910
	 *
1911
	 */
1912
	mail_compressFolder: function(action,_senders) {
1913
		this.egw.message(this.egw.lang('compress folder'));
1914
		egw.jsonq('mail.mail_ui.ajax_compressFolder',[_senders[0].iface.id]);
1915
		//	.sendRequest(true);
1916
		// since the json reply is using this.egw.refresh, we should not need to call refreshFolderStatus
1917
		// as the actions thereof are now bound to run after grid refresh
1918
		//this.mail_refreshFolderStatus();
1919
	},
1920
1921
	/**
1922
	 * mail_changeProfile
1923
	 *
1924
	 * @param {string} folder the ID of the selected Node -> should be an integer
1925
	 * @param {object} _widget handle to the tree widget
1926
	 * @param {boolean} getFolders Flag to indicate that the profile needs the mail
1927
	 *		folders.  False means they're already loaded in the tree, and we don't need
1928
	 *		them again
1929
	 */
1930
	mail_changeProfile: function(folder,_widget, getFolders) {
1931
		if(typeof getFolders == 'undefined')
1932
		{
1933
			getFolders = true;
1934
		}
1935
	//	alert(folder);
1936
		this.egw.message(this.egw.lang('Connect to Profile %1',_widget.getSelectedLabel().replace(this._unseen_regexp, '')));
1937
1938
		//Open unloaded tree to get loaded
1939
		_widget.openItem(folder, true);
1940
1941
		this.lock_tree();
1942
		egw.json('mail_ui::ajax_changeProfile',[folder, getFolders, this.et2._inst.etemplate_exec_id], jQuery.proxy(function() {
1943
			// Profile changed, select inbox
1944
			var inbox = folder + '::INBOX';
1945
			_widget.reSelectItem(inbox);
1946
			this.mail_changeFolder(inbox,_widget,'');
1947
			this.unlock_tree();
1948
		},this))
1949
			.sendRequest(true);
1950
1951
		return true;
1952
	},
1953
1954
	/**
1955
	 * mail_changeFolder
1956
	 * @param {string} _folder the ID of the selected Node
1957
	 * @param {widget object} _widget handle to the tree widget
1958
	 * @param {string} _previous - Previously selected node ID
1959
	 */
1960
	mail_changeFolder: function(_folder,_widget, _previous) {
1961
1962
		// to reset iframes to the normal status
1963
		this.loadIframe();
1964
1965
		// Abort if user selected an un-selectable node
1966
		// Use image over anything else because...?
1967
		var img = _widget.getSelectedNode().images[0];
1968
		if (img.indexOf('NoSelect') !== -1)
1969
		{
1970
			_widget.reSelectItem(_previous);
1971
			return;
1972
		}
1973
1974
		// Check if this is a top level node and
1975
		// change profile if server has changed
1976
		var server = _folder.split('::');
1977
		var previousServer = _previous.split('::');
1978
		var profile_selected = (_folder.indexOf('::') === -1);
1979
		if (server[0] != previousServer[0] && profile_selected)
1980
		{
1981
			// mail_changeProfile triggers a refresh, no need to do any more
1982
			return this.mail_changeProfile(_folder,_widget, _widget.getSelectedNode().childsCount == 0);
1983
		}
1984
1985
		// Apply new selected folder to list, which updates data
1986
		var nm = _widget.getRoot().getWidgetById(this.nm_index);
1987
		if(nm)
1988
		{
1989
			this.lock_tree();
1990
			nm.applyFilters({'selectedFolder': _folder});
1991
		}
1992
1993
		// Get nice folder name for message, if selected is not a profile
1994
		if(!profile_selected)
1995
		{
1996
			var displayname = _widget.getSelectedLabel();
1997
			var myMsg = (displayname?displayname:_folder).replace(this._unseen_regexp, '')+' '+this.egw.lang('selected');
1998
			this.egw.message(myMsg);
1999
		}
2000
2001
		// Update non-grid
2002
		this.mail_refreshFolderStatus(_folder,'forced',false,false);
2003
		this.mail_refreshQuotaDisplay(server[0]);
2004
		this.mail_preview();
2005
		if (server[0]!=previousServer[0])
2006
		{
2007
			this.mail_callRefreshVacationNotice(server[0]);
2008
			egw.jsonq('mail.mail_ui.ajax_refreshFilters',[server[0]]);
2009
		}
2010
	},
2011
2012
	/**
2013
	 * mail_checkAllSelected
2014
	 *
2015
	 * @param _action
2016
	 * @param _elems
2017
	 * @param _target
2018
	 * @param _confirm
2019
	 */
2020
	mail_checkAllSelected: function(_action, _elems, _target, _confirm)
2021
	{
2022
		if (typeof _confirm == 'undefined') _confirm = false;
2023
		// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
2024
		// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
2025
		var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
2026
		var that = this;
2027
		var rvMain = false;
2028
		if ((obj_manager && _elems.length>1 && obj_manager.getAllSelected() && !_action.paste) || _action.id=='readall')
2029
		{
2030
			if (_confirm)
2031
			{
2032
				var buttons = [
2033
					{text: this.egw.lang("Yes"), id: "all", "class": "ui-priority-primary", "default": true, image: 'check'},
2034
					{text: this.egw.lang("Cancel"), id:"cancel"}
2035
				];
2036
				var messageToDisplay = '';
2037
				var actionlabel =_action.id;
2038
				switch (_action.id)
2039
				{
2040
					case "readall":
2041
						messageToDisplay = this.egw.lang("Do you really want to mark ALL messages as read in the current folder?")+" ";
2042
						break;
2043
					case "unlabel":
2044
						messageToDisplay = this.egw.lang("Do you really want to remove ALL labels from ALL messages in the current folder?")+" ";
2045
						break;
2046
					case "label1":
2047
						if (_action.id=="label1") actionlabel="important";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2048
					case "label2":
2049
						if (_action.id=="label2") actionlabel="job";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2050
					case "label3":
2051
						if (_action.id=="label3") actionlabel="personal";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2052
					case "label4":
2053
						if (_action.id=="label4") actionlabel="to do";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
2054
					case "label5":
2055
						if (_action.id=="label5") actionlabel="later";
2056
					case "flagged":
2057
					case "read":
2058
					case "undelete":
2059
						messageToDisplay = this.egw.lang("Do you really want to toggle flag %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
2060
						if (_action.id.substr(0,5)=='label') messageToDisplay = this.egw.lang("Do you really want to toggle label %1 for ALL messages in the current view?",this.egw.lang(actionlabel))+" ";
2061
						break;
2062
					default:
2063
						var type = null;
2064
						if (_action.id.substr(0,4)=='move' || _action.id === "drop_move_mail")
2065
						{
2066
							type = 'Move';
2067
						}
2068
						if (_action.id.substr(0,4)=='copy' || _action.id === "drop_copy_mail")
2069
						{
2070
							type = 'Copy';
2071
						}
2072
						messageToDisplay = this.egw.lang("Do you really want to apply %1 to ALL messages in the current view?",this.egw.lang(type?type:_action.id))+" ";
2073
				}
2074
				return et2_dialog.show_dialog(function(_button_id) {
2075
					var rv = false;
2076
					switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2077
					{
2078
						case "all":
2079
							rv = true;
2080
							break;
2081
						case "cancel":
2082
							rv = 'cancel';
2083
					}
2084
					if (rv !="cancel") that.lock_tree();
2085
					switch (_action.id)
2086
					{
2087
						case "delete":
2088
							that.mail_callDelete(_action, _elems,rv);
2089
							break;
2090
						case "readall":
2091
						case "unlabel":
2092
						case "label1":
2093
						case "label2":
2094
						case "label3":
2095
						case "label4":
2096
						case "label5":
2097
						case "flagged":
2098
						case "read":
2099
						case "undelete":
2100
							that.mail_callFlagMessages(_action, _elems,rv);
2101
							break;
2102
						case "drop_move_mail":
2103
							that.mail_callMove(_action, _elems,_target, rv);
2104
							break;
2105
						case "drop_copy_mail":
2106
							that.mail_callCopy(_action, _elems,_target, rv);
2107
							break;
2108
						default:
2109
							if (_action.id.substr(0,4)=='move') that.mail_callMove(_action, _elems,_target, rv);
2110
							if (_action.id.substr(0,4)=='copy') that.mail_callCopy(_action, _elems,_target, rv);
2111
					}
2112
				},
2113
				messageToDisplay,
2114
				this.egw.lang("Confirm"),
2115
				_action.id, buttons);
2116
			}
2117
			else
2118
			{
2119
				rvMain = true;
2120
			}
2121
		}
2122
		switch (_action.id)
2123
		{
2124
			case "delete":
2125
				this.mail_callDelete(_action, _elems,rvMain);
2126
				break;
2127
			case "unlabel":
2128
			case "label1":
2129
			case "label2":
2130
			case "label3":
2131
			case "label4":
2132
			case "label5":
2133
			case "flagged":
2134
			case "read":
2135
			case "undelete":
2136
				this.mail_callFlagMessages(_action, _elems,rvMain);
2137
				break;
2138
			case "drop_move_mail":
2139
				this.mail_callMove(_action, _elems,_target, rvMain);
2140
				break;
2141
			case "drop_copy_mail":
2142
				this.mail_callCopy(_action, _elems,_target, rvMain);
2143
				break;
2144
			default:
2145
				if (_action.id.substr(0,4)=='move') this.mail_callMove(_action, _elems,_target, rvMain);
2146
				if (_action.id.substr(0,4)=='copy') this.mail_callCopy(_action, _elems,_target, rvMain);
2147
		}
2148
	},
2149
2150
	/**
2151
	 * mail_doActionCall
2152
	 *
2153
	 * @param _action
2154
	 * @param _elems
2155
	 */
2156
	mail_doActionCall: function(_action, _elems)
2157
	{
2158
	},
2159
2160
	/**
2161
	 * mail_getActiveFilters
2162
	 *
2163
	 * @param _action
2164
	 * @return mixed boolean/activeFilters object
2165
	 */
2166
	mail_getActiveFilters: function(_action)
2167
	{
2168
		// we can NOT query global object manager for this.nm_index="nm", as we might not get the one from mail,
2169
		// if other tabs are open, we have to query for obj_manager for "mail" and then it's child with id "nm"
2170
		var obj_manager = egw_getObjectManager(this.appname).getObjectById(this.nm_index);
2171
		if (obj_manager && obj_manager.manager && obj_manager.manager.data && obj_manager.manager.data.nextmatch && obj_manager.manager.data.nextmatch.activeFilters)
2172
		{
2173
			var af = obj_manager.manager.data.nextmatch.activeFilters;
2174
			// merge startdate and enddate into the active filters (if set)
2175
			if (this.et2.getWidgetById('startdate') && this.et2.getWidgetById('startdate').get_value()) af["startdate"] = this.et2.getWidgetById('startdate').date;
2176
			if (this.et2.getWidgetById('enddate') && this.et2.getWidgetById('enddate').get_value()) af["enddate"] = this.et2.getWidgetById('enddate').date;
2177
			return af;
2178
		}
2179
		return false;
2180
	},
2181
2182
	/**
2183
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2184
	 *
2185
	 * @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
2186
	 * @param _elems
2187
	 */
2188
	mail_flag: function(_action, _elems)
2189
	{
2190
		this.mail_checkAllSelected(_action,_elems,null,true);
2191
	},
2192
2193
	/**
2194
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2195
	 *
2196
	 * @param _action _action.id is 'read', 'unread', 'flagged' or 'unflagged'
2197
	 * @param _elems
2198
	 * @param _allMessagesChecked
2199
	 */
2200
	mail_callFlagMessages: function(_action, _elems, _allMessagesChecked)
2201
	{
2202
		/**
2203
		 * vars
2204
		 */
2205
		var folder = '',
2206
			tree = {},
2207
			formData = {},
2208
			data = {
2209
				msg: [this.et2.getArrayMgr("content").getEntry('mail_id')] || '',
2210
				all: _allMessagesChecked || false,
2211
				popup: typeof this.et2_view!='undefined' || egw(window).is_popup() || false,
2212
				activeFilters: _action.id == 'readall'? false : this.mail_getActiveFilters(_action)
2213
			},
2214
			rowClass = _action.id;
2215
2216
		if (typeof _elems === 'undefined' || _elems.length == 0)
2217
		{
2218
			if (this.mail_isMainWindow && this.mail_currentlyFocussed)
2219
			{
2220
				data.msg = [this.mail_currentlyFocussed];
2221
				_elems = data;
2222
				data.msg = this.mail_getFormData(_elems).msg;
2223
			}
2224
		}
2225
		else // action called by contextmenu
2226
		{
2227
			data.msg = this.mail_getFormData(_elems).msg;
2228
		}
2229
		switch (_action.id)
2230
		{
2231
			case 'read':
2232
				rowClass = 'seen';
2233
				if (data.popup)
2234
				{
2235
					var et_2 = typeof this.et2_view!='undefined'? etemplate2:opener.etemplate2;
2236
					tree = et_2.getByApplication('mail')[0].widgetContainer.getWidgetById(this.nm_index+'[foldertree]');
2237
				}
2238
				else
2239
				{
2240
					tree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
2241
				}
2242
				folder = tree.getSelectedNode().id;
2243
				break;
2244
			case 'readall':
2245
				rowClass = 'seen';
2246
				break;
2247
			case 'label1':
2248
				rowClass = 'labelone';
2249
				break;
2250
			case 'label2':
2251
				rowClass = 'labeltwo';
2252
				break;
2253
			case 'label3':
2254
				rowClass = 'labelthree';
2255
				break;
2256
			case 'label4':
2257
				rowClass = 'labelfour';
2258
				break;
2259
			case 'label5':
2260
				rowClass = 'labelfive';
2261
				break;
2262
			default:
2263
				break;
2264
		}
2265
		jQuery(data).extend({},data, formData);
2266
		if (data['all']=='cancel') return false;
2267
2268
		if (_action.id.substring(0,2)=='un') {
2269
			//old style, only available for undelete and unlabel (no toggle)
2270
			if ( _action.id=='unlabel') // this means all labels should be removed
2271
			{
2272
				var labels = ['labelone','labeltwo','labelthree','labelfour','labelfive'];
2273
				for (var i=0; i<labels.length; i++)	this.mail_removeRowClass(_elems,labels[i]);
2274
				this.mail_flagMessages(_action.id,data);
2275
			}
2276
			else
2277
			{
2278
				this.mail_removeRowClass(_elems,_action.id.substring(2));
2279
				this.mail_setRowClass(_elems,_action.id);
2280
				this.mail_flagMessages(_action.id,data);
2281
			}
2282
		}
2283
		else if (_action.id=='readall')
2284
		{
2285
			this.mail_flagMessages('read',data);
2286
		}
2287
		else
2288
		{
2289
			var msg_set = {msg:[]};
2290
			var msg_unset = {msg:[]};
2291
			var dataElem;
2292
			var flags;
2293
			var classes = '';
2294
			for (var i=0; i<data.msg.length; i++)
2295
			{
2296
				dataElem = egw.dataGetUIDdata(data.msg[i]);
2297
				if(typeof dataElem.data.flags == 'undefined')
2298
				{
2299
					dataElem.data.flags = {};
2300
				}
2301
				flags = dataElem.data.flags;
2302
				classes = dataElem.data['class'] || "";
2303
				classes = classes.split(' ');
2304
				// since we toggle we need to unset the ones already set, and set the ones not set
2305
				// flags is data, UI is done by class, so update both
2306
				// Flags are there or not, class names are flag or 'un'+flag
2307
				if(classes.indexOf(rowClass) >= 0)
2308
				{
2309
					classes.splice(classes.indexOf(rowClass),1);
2310
				}
2311
				if(classes.indexOf('un' + rowClass) >= 0)
2312
				{
2313
					classes.splice(classes.indexOf('un' + rowClass),1);
2314
				}
2315
				if (flags[_action.id])
2316
				{
2317
					msg_unset['msg'].push(data.msg[i]);
2318
					classes.push('un'+rowClass);
2319
					delete flags[_action.id];
2320
				}
2321
				else
2322
				{
2323
					msg_set['msg'].push(data.msg[i]);
2324
					flags[_action.id] = _action.id;
2325
					classes.push(rowClass);
2326
				}
2327
2328
				// Update cache & call callbacks - updates list
2329
				dataElem.data['class']  = classes.join(' ');
2330
				egw.dataStoreUID(data.msg[i],dataElem.data);
2331
2332
				//Refresh the nm rows after we told dataComponent about all changes, since the dataComponent doesn't talk to nm, we need to do it manually
2333
				this.updateFilter_data(data.msg[i], _action.id, data.activeFilters);
2334
			}
2335
2336
			// Notify server of changes
2337
			if (msg_unset['msg'] && msg_unset['msg'].length)
2338
			{
2339
				if (!data['all']) this.mail_flagMessages('un'+_action.id,msg_unset);
2340
			}
2341
			if (msg_set['msg'] && msg_set['msg'].length)
2342
			{
2343
				if (!data['all']) this.mail_flagMessages(_action.id,msg_set);
2344
			}
2345
			//server must do the toggle, as we apply to ALL, not only the visible
2346
			if (data['all']) this.mail_flagMessages(_action.id,data);
2347
			// No further update needed, only in case of read, the counters should be refreshed
2348
			if (_action.id=='read') this.mail_refreshFolderStatus(folder,'thisfolderonly',false,true);
2349
			return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
2350
		}
2351
	},
2352
2353
	/**
2354
	 * Update changes on filtered mail rows in nm, triggers manual refresh
2355
	 *
2356
	 * @param {type} _uid mail uid
2357
	 * @param {type} _actionId action id sended by nm action
2358
	 * @param {type} _filters activefilters
2359
	 */
2360
	updateFilter_data: function (_uid, _actionId, _filters)
2361
	{
2362
		var uid = _uid.replace('mail::','');
2363
		var action = '';
2364
		switch (_actionId)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
2365
		{
2366
			case 'flagged':
2367
				action = 'flagged';
2368
				break;
2369
			case 'read':
2370
				if (_filters.filter == 'seen')
2371
				{
2372
					action = 'seen';
2373
				}
2374
				else if (_filters.filter == 'unseen')
2375
				{
2376
					action = 'unseen';
2377
				}
2378
				break;
2379
			case 'label1':
2380
				action = 'keyword1';
2381
				break;
2382
			case 'label2':
2383
				action = 'keyword2';
2384
				break;
2385
			case 'label3':
2386
				action = 'keyword3';
2387
				break;
2388
			case 'label4':
2389
				action = 'keyword4';
2390
				break;
2391
			case 'label4':
2392
				action = 'keyword4';
2393
				break;
2394
		}
2395
		if (action == _filters.filter)
2396
		{
2397
			egw.refresh('','mail',uid, 'delete');
2398
		}
2399
	},
2400
2401
	/**
2402
	 * Flag mail as 'read', 'unread', 'flagged' or 'unflagged'
2403
	 *
2404
	 * @param {object} _flag
2405
	 * @param {object} _elems
2406
	 * @param {boolean} _isPopup
2407
	 */
2408
	mail_flagMessages: function(_flag, _elems,_isPopup)
2409
	{
2410
		egw.jsonq('mail.mail_ui.ajax_flagMessages',[_flag, _elems]);
2411
		//	.sendRequest(true);
2412
	},
2413
2414
	/**
2415
	 * display header lines, or source of mail, depending on the url given
2416
	 *
2417
	 * @param _url
2418
	 */
2419
	mail_displayHeaderLines: function(_url) {
2420
		// only used by right clickaction
2421
		egw_openWindowCentered(_url,'mail_display_headerLines','870','600',window.outerWidth/2,window.outerHeight/2);
2422
	},
2423
2424
	/**
2425
	 * View header of a message
2426
	 *
2427
	 * @param _action
2428
	 * @param _elems _elems[0].id is the row-id
2429
	 */
2430
	mail_header: function(_action, _elems)
2431
	{
2432
		if (typeof _elems == 'undefined'|| _elems.length==0)
2433
		{
2434
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2435
			{
2436
				var _elems = [];
2437
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2438
			}
2439
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2440
			{
2441
				if (this.mail_currentlyFocussed)
2442
				{
2443
					var _elems = [];
2444
					_elems.push({id:this.mail_currentlyFocussed});
2445
				}
2446
			}
2447
		}
2448
		//alert('mail_header('+_elems[0].id+')');
2449
		var url = window.egw_webserverUrl+'/index.php?';
2450
		url += 'menuaction=mail.mail_ui.displayHeader';	// todo compose for Draft folder
2451
		url += '&id='+_elems[0].id;
2452
		this.mail_displayHeaderLines(url);
2453
	},
2454
2455
	/**
2456
	 * View message source
2457
	 *
2458
	 * @param _action
2459
	 * @param _elems _elems[0].id is the row-id
2460
	 */
2461
	mail_mailsource: function(_action, _elems)
2462
	{
2463
		if (typeof _elems == 'undefined' || _elems.length==0)
2464
		{
2465
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2466
			{
2467
				var _elems = [];
2468
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2469
			}
2470
			if ((typeof _elems == 'undefined'|| _elems.length==0) && this.mail_isMainWindow)
2471
			{
2472
				if (this.mail_currentlyFocussed)
2473
				{
2474
					var _elems = [];
2475
					_elems.push({id:this.mail_currentlyFocussed});
2476
				}
2477
			}
2478
		}
2479
		//alert('mail_mailsource('+_elems[0].id+')');
2480
		var url = window.egw_webserverUrl+'/index.php?';
2481
		url += 'menuaction=mail.mail_ui.saveMessage';	// todo compose for Draft folder
2482
		url += '&id='+_elems[0].id;
2483
		url += '&location=display';
2484
		this.mail_displayHeaderLines(url);
2485
	},
2486
2487
	/**
2488
	 * Save a message
2489
	 *
2490
	 * @param _action
2491
	 * @param _elems _elems[0].id is the row-id
2492
	 */
2493
	mail_save: function(_action, _elems)
2494
	{
2495
		if (typeof _elems == 'undefined' || _elems.length==0)
2496
		{
2497
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2498
			{
2499
				var _elems = [];
2500
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2501
			}
2502
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2503
			{
2504
				if (this.mail_currentlyFocussed)
2505
				{
2506
					var _elems = [];
2507
					_elems.push({id:this.mail_currentlyFocussed});
2508
				}
2509
			}
2510
		}
2511
		//alert('mail_save('+_elems[0].id+')');
2512
		var url = window.egw_webserverUrl+'/index.php?';
2513
		url += 'menuaction=mail.mail_ui.saveMessage';	// todo compose for Draft folder
2514
		url += '&id='+_elems[0].id;
2515
		//window.open(url,'_blank','dependent=yes,width=100,height=100,scrollbars=yes,status=yes');
2516
		this.et2._inst.download(url);
2517
	},
2518
2519
	/**
2520
	 * User clicked an address (FROM, TO, etc)
2521
	 *
2522
	 * @param {object} tag_info with values for attributes id, label, title, ...
2523
	 * @param {widget object} widget
2524
	 *
2525
	 * @todo seems this function is not implemented, need to be checked if it is neccessary at all
2526
	 */
2527
	address_click: function(tag_info, widget)
2528
	{
2529
2530
	},
2531
2532
	/**
2533
	 * displayAttachment
2534
	 *
2535
	 * @param {object} tag_info
2536
	 * @param {widget object} widget
2537
	 * @param {object} calledForCompose
2538
	 */
2539
	displayAttachment: function(tag_info, widget, calledForCompose)
2540
	{
2541
		var mailid;
2542
		var attgrid;
2543
		if (typeof calledForCompose == 'undefined' || typeof calledForCompose == 'object') calledForCompose=false;
2544
		if (calledForCompose===false)
2545
		{
2546
			if (this.mail_isMainWindow)
2547
			{
2548
				mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2549
				var p = widget.getParent();
2550
				var cont = p.getArrayMgr("content").data;
2551
				attgrid = cont[widget.id.replace(/\[filename\]/,'')];
2552
			}
2553
			else
2554
			{
2555
				mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2556
				attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[filename\]/,'')];
2557
			}
2558
		}
2559
		if (calledForCompose===true)
2560
		{
2561
			// CALLED FOR COMPOSE; processedmail_id could hold several IDs seperated by comma
2562
			attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
2563
			var mailids = this.et2.getArrayMgr("content").getEntry('processedmail_id');
2564
			var mailida = mailids.split(',');
2565
			// either several attachments of one email, or multiple emlfiles
2566
			mailid = mailida.length==1 ? mailida[0] : mailida[widget.id.replace(/\[name\]/,'')];
2567
			if (typeof attgrid.uid != 'undefined' && attgrid.uid && mailid.indexOf(attgrid.uid)==-1)
2568
			{
2569
				for (var i=0; i<mailida.length; i++)
2570
				{
2571
					if (mailida[i].indexOf('::'+attgrid.uid)>-1) mailid = mailida[i];
2572
				}
2573
			}
2574
		}
2575
		var url = window.egw_webserverUrl+'/index.php?';
2576
		var width;
2577
		var height;
2578
		var windowName ='mail';
2579
		switch(attgrid.type.toUpperCase())
0 ignored issues
show
Bug introduced by
The variable attgrid does not seem to be initialized in case calledForCompose === false on line 2544 is false. Are you sure this can never be the case?
Loading history...
2580
		{
2581
			case 'MESSAGE/RFC822':
2582
				url += 'menuaction=mail.mail_ui.displayMessage';	// todo compose for Draft folder
2583
				url += '&mode=display';//message/rfc822 attachments should be opened in display mode
2584
				url += '&id='+mailid;
0 ignored issues
show
Bug introduced by
The variable mailid does not seem to be initialized in case calledForCompose === false on line 2544 is false. Are you sure this can never be the case?
Loading history...
2585
				url += '&part='+attgrid.partID;
2586
				url += '&is_winmail='+attgrid.winmailFlag;
2587
				windowName = windowName+'displayMessage_'+mailid+'_'+attgrid.partID;
2588
				width = 870;
2589
				height = egw_getWindowOuterHeight();
2590
				break;
2591
			case 'IMAGE/JPEG':
2592
			case 'IMAGE/PNG':
2593
			case 'IMAGE/GIF':
2594
			case 'IMAGE/BMP':
2595
			case 'APPLICATION/PDF':
2596
			case 'TEXT/PLAIN':
2597
			case 'TEXT/HTML':
2598
			case 'TEXT/DIRECTORY':
2599
/*
2600
				$sfxMimeType = $value['mimeType'];
2601
				$buff = explode('.',$value['name']);
2602
				$suffix = '';
2603
				if (is_array($buff)) $suffix = array_pop($buff); // take the last extension to check with ext2mime
2604
				if (!empty($suffix)) $sfxMimeType = mime_magic::ext2mime($suffix);
2605
				if (strtoupper($sfxMimeType) == 'TEXT/VCARD' || strtoupper($sfxMimeType) == 'TEXT/X-VCARD')
2606
				{
2607
					$attachments[$key]['mimeType'] = $sfxMimeType;
2608
					$value['mimeType'] = strtoupper($sfxMimeType);
2609
				}
2610
*/
2611
			case 'TEXT/X-VCARD':
2612
			case 'TEXT/VCARD':
2613
			case 'TEXT/CALENDAR':
2614
			case 'TEXT/X-VCALENDAR':
2615
				url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2616
				url += '&id='+mailid;
2617
				url += '&part='+attgrid.partID;
2618
				url += '&is_winmail='+attgrid.winmailFlag;
2619
				windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
2620
				var reg = '800x600';
2621
				var reg2;
2622
				// handle calendar/vcard
2623
				if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
2624
				{
2625
					windowName = 'maildisplayEvent_'+mailid+'_'+attgrid.partID;
2626
					reg2 = egw.link_get_registry('calendar');
2627
					if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
2628
					{
2629
						reg = reg2['view_popup'];
2630
					}
2631
				}
2632
				if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
2633
				{
2634
					windowName = 'maildisplayContact_'+mailid+'_'+attgrid.partID;
2635
					reg2 = egw.link_get_registry('addressbook');
2636
					if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
2637
					{
2638
						reg = reg2['add_popup'];
2639
					}
2640
				}
2641
				var w_h =reg.split('x');
2642
				width = w_h[0];
2643
				height = w_h[1];
2644
				break;
2645
			default:
2646
				url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2647
				url += '&id='+mailid;
2648
				url += '&part='+attgrid.partID;
2649
				url += '&is_winmail='+attgrid.winmailFlag;
2650
				windowName = windowName+'displayAttachment_'+mailid+'_'+attgrid.partID;
2651
				width = 870;
2652
				height = 600;
2653
				break;
2654
		}
2655
		egw_openWindowCentered(url,windowName,width,height);
2656
	},
2657
2658
	/**
2659
	 * displayUploadedFile
2660
	 *
2661
	 * @param {object} tag_info
2662
	 * @param {widget object} widget
2663
	 */
2664
	displayUploadedFile: function(tag_info, widget)
2665
	{
2666
		var attgrid;
2667
		attgrid = this.et2.getArrayMgr("content").getEntry('attachments')[widget.id.replace(/\[name\]/,'')];
2668
2669
		if (attgrid.uid && (attgrid.partID||attgrid.folder))
2670
		{
2671
			this.displayAttachment(tag_info, widget, true);
2672
			return;
2673
		}
2674
		var get_param = {
2675
			menuaction: 'mail.mail_compose.getAttachment',	// todo compose for Draft folder
2676
			tmpname: attgrid.tmp_name,
2677
			etemplate_exec_id: this.et2._inst.etemplate_exec_id
2678
		};
2679
		var width;
2680
		var height;
2681
		var windowName ='maildisplayAttachment_'+attgrid.file.replace(/\//g,"_");
2682
		switch(attgrid.type.toUpperCase())
2683
		{
2684
			case 'IMAGE/JPEG':
2685
			case 'IMAGE/PNG':
2686
			case 'IMAGE/GIF':
2687
			case 'IMAGE/BMP':
2688
			case 'APPLICATION/PDF':
2689
			case 'TEXT/PLAIN':
2690
			case 'TEXT/HTML':
2691
			case 'TEXT/DIRECTORY':
2692
			case 'TEXT/X-VCARD':
2693
			case 'TEXT/VCARD':
2694
			case 'TEXT/CALENDAR':
2695
			case 'TEXT/X-VCALENDAR':
2696
				var reg = '800x600';
2697
				var reg2;
2698
				// handle calendar/vcard
2699
				if (attgrid.type.toUpperCase()=='TEXT/CALENDAR')
2700
				{
2701
					windowName = 'maildisplayEvent_'+attgrid.file.replace(/\//g,"_");
2702
					reg2 = egw.link_get_registry('calendar');
2703
					if (typeof reg2['view'] != 'undefined' && typeof reg2['view_popup'] != 'undefined' )
2704
					{
2705
						reg = reg2['view_popup'];
2706
					}
2707
				}
2708
				if (attgrid.type.toUpperCase()=='TEXT/X-VCARD' || attgrid.type.toUpperCase()=='TEXT/VCARD')
2709
				{
2710
					windowName = 'maildisplayContact_'+attgrid.file.replace(/\//g,"_");
2711
					reg2 = egw.link_get_registry('addressbook');
2712
					if (typeof reg2['add'] != 'undefined' && typeof reg2['add_popup'] != 'undefined' )
2713
					{
2714
						reg = reg2['add_popup'];
2715
					}
2716
				}
2717
				var w_h =reg.split('x');
2718
				width = w_h[0];
2719
				height = w_h[1];
2720
				break;
2721
			case 'MESSAGE/RFC822':
2722
			default:
2723
				get_param.mode = 'save';
2724
				width = 870;
2725
				height = 600;
2726
				break;
2727
		}
2728
		egw.openPopup(egw.link('/index.php', get_param), width, height, windowName);
2729
	},
2730
2731
	saveAttachment: function(tag_info, widget)
2732
	{
2733
		var mailid;
2734
		var attgrid;
2735
		if (this.mail_isMainWindow)
2736
		{
2737
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2738
			var p = widget.getParent();
2739
			var cont = p.getArrayMgr("content").data;
2740
			attgrid = cont[widget.id.replace(/\[save\]/,'')];
2741
		}
2742
		else
2743
		{
2744
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2745
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
2746
		}
2747
		var url = window.egw_webserverUrl+'/index.php?';
2748
		url += 'menuaction=mail.mail_ui.getAttachment';	// todo compose for Draft folder
2749
		url += '&mode=save';
2750
		url += '&id='+mailid;
2751
		url += '&part='+attgrid.partID;
2752
		url += '&is_winmail='+attgrid.winmailFlag;
2753
		this.et2._inst.download(url);
2754
	},
2755
2756
	saveAllAttachmentsToZip: function(tag_info, widget)
2757
	{
2758
		var mailid;
2759
		var attgrid;
2760
		if (this.mail_isMainWindow)
2761
		{
2762
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2763
			var p = widget.getParent();
2764
			var cont = p.getArrayMgr("content").data;
2765
			attgrid = cont[widget.id.replace(/\[save\]/,'')];
2766
		}
2767
		else
2768
		{
2769
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2770
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[save\]/,'')];
2771
		}
2772
		var url = window.egw_webserverUrl+'/index.php?';
2773
		url += 'menuaction=mail.mail_ui.download_zip';	// todo compose for Draft folder
2774
		url += '&mode=save';
2775
		url += '&id='+mailid;
2776
		this.et2._inst.download(url);
2777
	},
2778
2779
	saveAttachmentToVFS: function(tag_info, widget)
2780
	{
2781
		var mailid;
2782
		var attgrid;
2783
		if (this.mail_isMainWindow)
2784
		{
2785
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2786
			var p = widget.getParent();
2787
			var cont = p.getArrayMgr("content").data;
2788
			attgrid = cont[widget.id.replace(/\[saveAsVFS\]/,'')];
2789
		}
2790
		else
2791
		{
2792
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2793
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments')[widget.id.replace(/\[saveAsVFS\]/,'')];
2794
		}
2795
		var url = window.egw_webserverUrl+'/index.php?';
2796
		var width=640;
2797
		var height=570;
2798
		var windowName ='mail';
2799
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2800
		url += '&mode=saveas';
2801
		url += '&id='+mailid+'::'+attgrid.partID+'::'+attgrid.winmailFlag;
2802
		url += '&name='+attgrid.filename;
2803
		url += '&type='+attgrid.type.toLowerCase();
2804
		url += '&method=mail.mail_ui.vfsSaveAttachment';
2805
		url += '&label='+egw.lang('Save');
2806
		egw_openWindowCentered(url,windowName,width,height);
2807
	},
2808
2809
	saveAllAttachmentsToVFS: function(tag_info, widget)
2810
	{
2811
		var mailid;
2812
		var attgrid;
2813
		if (this.mail_isMainWindow)
2814
		{
2815
			mailid = this.mail_currentlyFocussed;//this.et2.getArrayMgr("content").getEntry('mail_id');
2816
			var p = widget.getParent();
2817
			attgrid = p.getArrayMgr("content").data;
2818
		}
2819
		else
2820
		{
2821
			mailid = this.et2.getArrayMgr("content").getEntry('mail_id');
2822
			attgrid = this.et2.getArrayMgr("content").getEntry('mail_displayattachments');
2823
		}
2824
		var url = window.egw_webserverUrl+'/index.php?';
2825
		var width=640;
2826
		var height=570;
2827
		var windowName ='mail';
2828
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2829
		url += '&mode=select-dir';
2830
		url += '&method=mail.mail_ui.vfsSaveAttachment';
2831
		url += '&label='+egw.lang('Save all');
2832
		for (var i=0;i<attgrid.length;i++)
2833
		{
2834
			if (attgrid[i] != null) url += '&id['+i+']='+mailid+'::'+attgrid[i].partID+'::'+attgrid[i].winmailFlag+'::'+attgrid[i].filename;
2835
		}
2836
		egw_openWindowCentered(url,windowName,width,height);
2837
	},
2838
2839
	/**
2840
	 * Save a message to filemanager
2841
	 *
2842
	 * @param _action
2843
	 * @param _elems _elems[0].id is the row-id
2844
	 */
2845
	mail_save2fm: function(_action, _elems)
2846
	{
2847
		if (typeof _elems == 'undefined' || _elems.length==0)
2848
		{
2849
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2850
			{
2851
				var _elems = [];
2852
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2853
			}
2854
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2855
			{
2856
				if (this.mail_currentlyFocussed)
2857
				{
2858
					var _elems = [];
2859
					_elems.push({id:this.mail_currentlyFocussed});
2860
				}
2861
			}
2862
		}
2863
		var _id = _elems[0].id;
2864
		var dataElem = egw.dataGetUIDdata(_id);
2865
		var url = window.egw_webserverUrl+'/index.php?';
2866
		url += 'menuaction=filemanager.filemanager_select.select';	// todo compose for Draft folder
2867
		url += '&mode=saveas';
2868
		var subject = dataElem? dataElem.data.subject: _elems[0].subject;
2869
		var filename = subject.replace(/[\f\n\t\v]/g,"_")|| 'unknown';
2870
		url += '&name='+encodeURIComponent(filename+'.eml');
2871
		url += '&mime=message'+encodeURIComponent('/')+'rfc822';
2872
		url += '&method=mail.mail_ui.vfsSaveMessage';
2873
		url += '&id='+_elems[0].id;
2874
		url += '&label=Save';
2875
		egw_openWindowCentered(url,'vfs_save_message_'+_elems[0].id,'680','400',window.outerWidth/2,window.outerHeight/2);
2876
2877
	},
2878
2879
	/**
2880
	 * Integrate mail message into another app's entry
2881
	 *
2882
	 * @param _action
2883
	 * @param _elems _elems[0].id is the row-id
2884
	 */
2885
	mail_integrate: function(_action, _elems)
2886
	{
2887
		var app = _action.id;
2888
		var w_h = ['750','580']; // define a default wxh if there's no popup size registered
2889
2890
		if (typeof _action.data != 'undefined' )
2891
		{
2892
			if (typeof _action.data.popup != 'undefined' && _action.data.popup) w_h = _action.data.popup.split('x');
2893
			if (typeof _action.data.mail_import != 'undefined') var mail_import_hook = _action.data.mail_import;
2894
		}
2895
2896
		if (typeof _elems == 'undefined' || _elems.length==0)
2897
		{
2898
			if (this.et2.getArrayMgr("content").getEntry('mail_id'))
2899
			{
2900
				var _elems = [];
2901
				_elems.push({id:this.et2.getArrayMgr("content").getEntry('mail_id') || ''});
2902
			}
2903
			if ((typeof _elems == 'undefined' || _elems.length==0) && this.mail_isMainWindow)
2904
			{
2905
				if (this.mail_currentlyFocussed)
2906
				{
2907
					var _elems = [];
2908
					_elems.push({id:this.mail_currentlyFocussed});
2909
				}
2910
			}
2911
		}
2912
2913
		var url = window.egw_webserverUrl+ '/index.php?menuaction=mail.mail_integration.integrate&rowid=' + _elems[0].id + '&app='+app;
2914
2915
		if (mail_import_hook && typeof mail_import_hook.app_entry_method != 'undefined')
2916
		{
2917
			var data = egw.dataGetUIDdata(_elems[0].id);
2918
			var subject = (data && typeof data.data != 'undefined')? data.data.subject : '';
2919
			this.integrate_checkAppEntry('Select '+ app + ' entry', app, subject, url,  mail_import_hook.app_entry_method, function (args){
2920
				egw_openWindowCentered(args.url+ (args.entryid ?'&entry_id=' + args.entryid: ''),'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
2921
			});
2922
		}
2923
		else
2924
		{
2925
			egw_openWindowCentered(url,'import_mail_'+_elems[0].id,w_h[0],w_h[1]);
2926
		}
2927
2928
	},
2929
2930
   /**
2931
	* Checks the application entry existance and offers user
2932
	* to select desire app id to append mail content into it,
2933
	* or add the mail content as a new app entry
2934
	*
2935
	* @param {string} _title select app entry title
2936
	* @param {string} _appName app to be integrated
2937
	* @param {string} _subject
2938
	* @param {string} _url
2939
	* @param {string} _appCheckCallback registered mail_import hook method
2940
	* @param {function} _execCallback function to get called on dialog actions
2941
	*/
2942
	integrate_checkAppEntry: function (_title, _appName, _subject ,_url, _appCheckCallback, _execCallback)
2943
	{
2944
	   var subject = _subject || '';
2945
	   var execCallback = _execCallback;
2946
	   egw.json(_appCheckCallback, subject,function(_entryId){
2947
2948
		   // if there's no entry saved already
2949
		   // open dialog in order to select one
2950
		   if (!_entryId)
2951
		   {
2952
			   var buttons = [
2953
				   {text: 'Append', id: 'append', image: 'check', default:true},
2954
				   {text: 'Add as new', id: 'new', image: 'check'},
2955
				   {text: 'Cancel', id: 'cancel', image: 'check'}
2956
			   ];
2957
			   et2_createWidget("dialog",
2958
			   {
2959
				   callback: function(_buttons, _value)
2960
				   {
2961
					   if (_buttons == 'cancel') return;
2962
					   if (_buttons == 'append' && _value)
2963
					   {
2964
						   _entryId = _value.id;
2965
					   }
2966
					   execCallback.call(this,{entryid:_entryId,url:_url});
2967
				   },
2968
				   title: egw.lang(_title),
2969
				   buttons: buttons||et2_dialog.BUTTONS_OK_CANCEL,
2970
				   value:{
2971
					   content:{
2972
						   appName:_appName // appName to search on its list later
2973
				   }},
2974
				   template: egw.webserverUrl+'/mail/templates/default/integration_to_entry_dialog.xet'
2975
			   },et2_dialog._create_parent('mail'));
2976
		   }
2977
		   else // there is an entry saved related to this mail's subject
2978
		   {
2979
			   execCallback.call(this,{entryid:_entryId,url:_url});
2980
		   }
2981
	   },this,true,this).sendRequest();
2982
	},
2983
2984
	/**
2985
	 * mail_getFormData
2986
	 *
2987
	 * @param {object} _actionObjects the senders
2988
	 *
2989
	 * @return structured array of message ids: array(msg=>message-ids)
2990
	 */
2991
	mail_getFormData: function(_actionObjects) {
2992
		var messages = {};
2993
		// if
2994
		if (typeof _actionObjects['msg'] != 'undefined' && _actionObjects['msg'].length>0) return _actionObjects;
2995
		if (_actionObjects.length>0)
2996
		{
2997
			messages['msg'] = [];
2998
		}
2999
3000
		for (var i = 0; i < _actionObjects.length; i++)
3001
		{
3002
			if (_actionObjects[i].id.length>0)
3003
			{
3004
				messages['msg'][i] = _actionObjects[i].id;
3005
			}
3006
		}
3007
3008
		return messages;
3009
	},
3010
3011
	/**
3012
	 * mail_setRowClass
3013
	 *
3014
	 * @param {object} _actionObjects the senders
3015
	 * @param {string} _class
3016
	 */
3017
	mail_setRowClass: function(_actionObjects,_class) {
3018
		if (typeof _class == 'undefined') return false;
3019
3020
		if (typeof _actionObjects['msg'] == 'undefined')
3021
		{
3022
			for (var i = 0; i < _actionObjects.length; i++)
3023
			{
3024
				// Check that the ID & interface is there.  Paste is missing iface.
3025
				if (_actionObjects[i].id.length>0 && _actionObjects[i].iface)
3026
				{
3027
					var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
3028
					dataElem.addClass(_class);
3029
3030
				}
3031
			}
3032
		}
3033
		else
3034
		{
3035
			for (var i = 0; i < _actionObjects['msg'].length; i++)
3036
			{
3037
				var mail_uid = _actionObjects['msg'][i];
3038
3039
				// Get the record from data cache
3040
				var dataElem = egw.dataGetUIDdata(mail_uid);
3041
				if(dataElem == null || typeof dataElem == undefined)
3042
				{
3043
					// Unknown ID, nothing to update
3044
					return;
3045
				}
3046
3047
				// Update class
3048
				dataElem.data['class']  += ' ' + _class;
3049
3050
				// need to update flags too
3051
				switch(_class)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3052
				{
3053
					case 'unseen':
3054
						delete dataElem.data.flags.read;
3055
						break;
3056
				}
3057
3058
				// Update record, which updates all listeners (including nextmatch)
3059
				egw.dataStoreUID(mail_uid,dataElem.data);
3060
			}
3061
		}
3062
	},
3063
3064
	/**
3065
	 * mail_removeRowFlag
3066
	 * Removes a flag and updates the CSS class.  Updates the UI, but not the server.
3067
	 *
3068
	 * @param {action object} _actionObjects the senders, or a messages object
3069
	 * @param {string} _class the class to be removed
3070
	 */
3071
	mail_removeRowClass: function(_actionObjects,_class) {
3072
		if (typeof _class == 'undefined') return false;
3073
3074
		if (typeof _actionObjects['msg'] == 'undefined')
3075
		{
3076
			for (var i = 0; i < _actionObjects.length; i++)
3077
			{
3078
				if (_actionObjects[i].id.length>0)
3079
				{
3080
					var dataElem = jQuery(_actionObjects[i].iface.getDOMNode());
3081
					dataElem.removeClass(_class);
3082
3083
				}
3084
			}
3085
		}
3086
		else
3087
		{
3088
			for (var i = 0; i < _actionObjects['msg'].length; i++)
3089
			{
3090
				var mail_uid = _actionObjects['msg'][i];
3091
3092
				// Get the record from data cache
3093
				var dataElem = egw.dataGetUIDdata(mail_uid);
3094
				if(dataElem == null || typeof dataElem == undefined)
3095
				{
3096
					// Unknown ID, nothing to update
3097
					return;
3098
				}
3099
3100
				// Update class
3101
				var classes = dataElem.data['class'] || "";
3102
				classes = classes.split(' ');
3103
				if(classes.indexOf(_class) >= 0)
3104
				{
3105
					classes.splice(classes.indexOf(_class),1);
3106
					dataElem.data['class'] = classes.join(' ');
3107
3108
					// need to update flags too
3109
					switch(_class)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3110
					{
3111
						case 'unseen':
3112
							dataElem.data.flags.read = true;
3113
							break;
3114
					}
3115
3116
					// Update record, which updates all listeners (including nextmatch)
3117
					egw.dataStoreUID(mail_uid,dataElem.data);
3118
				}
3119
			}
3120
		}
3121
	},
3122
3123
	/**
3124
	 * mail_move2folder - implementation of the move action from action menu
3125
	 *
3126
	 * @param _action _action.id holds folder target information
3127
	 * @param _elems - the representation of the elements to be affected
3128
	 */
3129
	mail_move2folder: function(_action, _elems) {
3130
		this.mail_move(_action, _elems, null);
3131
	},
3132
3133
	/**
3134
	 * mail_move - implementation of the move action from drag n drop
3135
	 *
3136
	 * @param _action
3137
	 * @param _senders - the representation of the elements dragged
3138
	 * @param _target - the representation of the target
3139
	 */
3140
	mail_move: function(_action,_senders,_target) {
3141
		this.mail_checkAllSelected(_action,_senders,_target,true);
3142
	},
3143
3144
	/**
3145
	 * mail_move - implementation of the move action from drag n drop
3146
	 *
3147
	 * @param _action
3148
	 * @param _senders - the representation of the elements dragged
3149
	 * @param _target - the representation of the target
3150
	 * @param _allMessagesChecked
3151
	 */
3152
	mail_callMove: function(_action,_senders,_target,_allMessagesChecked) {
3153
		var target = _action.id == 'drop_move_mail' ? _target.iface.id : _action.id.substr(5);
3154
		var messages = this.mail_getFormData(_senders);
3155
		if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
3156
3157
		// Directly delete any cache for target
3158
		if(window.localStorage)
3159
		{
3160
			for(var i = 0; i < window.localStorage.length; i++)
3161
			{
3162
				var key = window.localStorage.key(i);
3163
3164
				// Find directly by what the key would look like
3165
				if(key.indexOf('cached_fetch_mail::{"selectedFolder":"'+target+'"') == 0)
3166
				{
3167
					window.localStorage.removeItem(key);
3168
				}
3169
			}
3170
		}
3171
		// TODO: Write move/copy function which cares about doing the same stuff
3172
		// as the "onNodeSelect" function!
3173
		messages['all'] = _allMessagesChecked;
3174
		if (messages['all']=='cancel') return false;
3175
		if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
3176
3177
		// Make sure a default target folder is set in case of drop target is parent 0 (mail account name)
3178
		if (!target.match(/::/g)) target += '::INBOX';
3179
3180
		var self = this;
3181
		var nm = this.et2.getWidgetById(this.nm_index);
3182
		// thev 4th param indicates if it is a normal move messages action. if not the action is a move2.... (archiveFolder) action
3183
		egw.json('mail.mail_ui.ajax_copyMessages',[target, messages, 'move', (_action.id.substr(0,4)=='move'&&_action.id.substr(4,1)=='2'?'2':'_') ], function(){
3184
			self.unlock_tree();
3185
			// Nextmatch automatically selects the next row and calls preview.
3186
			// Unselect it and thanks to the timeout selectionMgr uses, preview
3187
			// will close when the selection callback fires instead of load the
3188
			// next message
3189
			nm.controller._selectionMgr.resetSelection();
3190
3191
			// Server response may contain refresh, but it's always delete
3192
			// Refresh list if current view is the target (happens when pasting)
3193
			var tree = self.et2.getWidgetById('nm[foldertree]');
3194
			if(nm && tree && target == tree.getValue())
3195
			{
3196
				// Can't trust the sorting, needs to be full refresh
3197
				nm.refresh();
3198
			}
3199
		})
3200
			.sendRequest();
3201
		this.mail_setRowClass(_senders,'deleted');
3202
		// Server response may contain refresh, not needed here
3203
	},
3204
3205
	/**
3206
	 * mail_copy - implementation of the move action from drag n drop
3207
	 *
3208
	 * @param _action
3209
	 * @param _senders - the representation of the elements dragged
3210
	 * @param _target - the representation of the target
3211
	 */
3212
	mail_copy: function(_action,_senders,_target) {
3213
		this.mail_checkAllSelected(_action,_senders,_target,true);
3214
	},
3215
3216
	/**
3217
	 * mail_callCopy - implementation of the copy action from drag n drop
3218
	 *
3219
	 * @param _action
3220
	 * @param _senders - the representation of the elements dragged
3221
	 * @param _target - the representation of the target
3222
	 * @param _allMessagesChecked
3223
	 */
3224
	mail_callCopy: function(_action,_senders,_target,_allMessagesChecked) {
3225
		var target = _action.id == 'drop_copy_mail' ? _target.iface.id : _action.id.substr(5);
3226
		var messages = this.mail_getFormData(_senders);
3227
		if (typeof _allMessagesChecked=='undefined') _allMessagesChecked=false;
3228
		// TODO: Write move/copy function which cares about doing the same stuff
3229
		// as the "onNodeSelect" function!
3230
		messages['all'] = _allMessagesChecked;
3231
		if (messages['all']=='cancel') return false;
3232
		if (messages['all']) messages['activeFilters'] = this.mail_getActiveFilters(_action);
3233
		var self = this;
3234
		egw.json('mail.mail_ui.ajax_copyMessages',[target, messages],function (){self.unlock_tree();})
3235
			.sendRequest();
3236
		// Server response contains refresh
3237
	},
3238
3239
	/**
3240
	 * mail_AddFolder - implementation of the AddFolder action of right click options on the tree
3241
	 *
3242
	 * @param _action
3243
	 * @param _senders - the representation of the tree leaf to be manipulated
3244
	 */
3245
	mail_AddFolder: function(_action,_senders) {
3246
		//action.id == 'add'
3247
		//_senders.iface.id == target leaf / leaf to edit
3248
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3249
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3250
		var buttons = [
3251
			{text: this.egw.lang("Add"), id: "add", "class": "ui-priority-primary", "default": true},
3252
			{text: this.egw.lang("Cancel"), id:"cancel"}
3253
		];
3254
		et2_dialog.show_prompt(function(_button_id, _value) {
3255
			var NewFolderName = null;
3256
			if (_value.length>0) NewFolderName = _value;
3257
			//alert(NewFolderName);
3258
			if (NewFolderName && NewFolderName.length>0)
3259
			{
3260
				switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3261
				{
3262
					case "add":
3263
						egw.json('mail.mail_ui.ajax_addFolder',[_senders[0].id, NewFolderName])
3264
							.sendRequest(true);
3265
						return;
3266
					case "cancel":
3267
				}
3268
			}
3269
		},
3270
		this.egw.lang("Enter the name for the new Folder:"),
3271
		this.egw.lang("Add a new Folder to %1:",OldFolderName),
3272
		'', buttons);
3273
	},
3274
3275
	/**
3276
	 * mail_RenameFolder - implementation of the RenameFolder action of right click options on the tree
3277
	 *
3278
	 * @param _action
3279
	 * @param _senders - the representation of the tree leaf to be manipulated
3280
	 */
3281
	mail_RenameFolder: function(_action,_senders) {
3282
		//action.id == 'rename'
3283
		//_senders.iface.id == target leaf / leaf to edit
3284
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3285
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3286
		var buttons = [
3287
			{text: this.egw.lang("Rename"), id: "rename", "class": "ui-priority-primary", image: 'edit', "default": true},
3288
			{text: this.egw.lang("Cancel"), id:"cancel"}
3289
		];
3290
		et2_dialog.show_prompt(function(_button_id, _value) {
3291
			var NewFolderName = null;
3292
			if (_value.length>0) NewFolderName = _value;
3293
			//alert(NewFolderName);
3294
			if (NewFolderName && NewFolderName.length>0)
3295
			{
3296
				switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3297
				{
3298
					case "rename":
3299
						egw.json('mail.mail_ui.ajax_renameFolder',[_senders[0].id, NewFolderName])
3300
							.sendRequest(true);
3301
						return;
3302
					case "cancel":
3303
				}
3304
			}
3305
		},
3306
		this.egw.lang("Rename Folder %1 to:",OldFolderName),
3307
		this.egw.lang("Rename Folder %1 ?",OldFolderName),
3308
		OldFolderName, buttons);
3309
	},
3310
3311
	/**
3312
	 * mail_MoveFolder - implementation of the MoveFolder action on the tree
3313
	 *
3314
	 * @param {egwAction} _action
3315
	 * @param {egwActionObject[]} _senders - the representation of the tree leaf to be manipulated
3316
	 * @param {egwActionObject} destination Drop target egwActionObject representing the destination
3317
	 */
3318
	mail_MoveFolder: function(_action,_senders,destination) {
3319
		if(!destination || !destination.id)
3320
		{
3321
			egw.debug('warn', "Move folder, but no target");
3322
			return;
3323
		}
3324
		var sourceProfile = _senders[0].id.split('::');
3325
		var targetProfile = destination.id.split('::');
3326
		if (sourceProfile[0]!=targetProfile[0])
3327
		{
3328
			egw.message(this.egw.lang('Moving Folders from one Mailaccount to another is not supported'),'error');
3329
			return;
3330
		}
3331
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3332
		var src_label = _senders[0].id.replace(/^[0-9]+::/,'');
3333
		var dest_label = destination.id.replace(/^[0-9]+::/,'');
3334
3335
		var callback = function (_button)
3336
		{
3337
			if (_button == et2_dialog.YES_BUTTON)
3338
			{
3339
				egw.appName='mail';
3340
				egw.message (egw.lang('Folder %1 is moving to folder %2',src_label,dest_label ));
3341
				egw.loading_prompt('mail_moveFolder', true,'','#egw_fw_basecontainer');
3342
				for(var i = 0; i < _senders.length; i++)
3343
				{
3344
					egw.jsonq('mail.mail_ui.ajax_MoveFolder',[_senders[i].id, destination.id],
3345
						// Move is done (successfully or not), remove loading
3346
						function() {
3347
							var id = destination.id.split('::');
3348
							//refersh the top parent
3349
							ftree.refreshItem(id[0],null);
3350
							egw.loading_prompt('mail_moveFolder', false);
3351
						}
3352
					);
3353
				}
3354
			}
3355
		};
3356
		et2_dialog.show_dialog(callback, this.egw.lang('Are you sure you want to move folder %1 to folder %2?',
3357
			src_label, dest_label), this.egw.lang('Move folder'), {},et2_dialog.BUTTONS_YES_NO,  et2_dialog.WARNING_MESSAGE);
3358
	},
3359
3360
	/**
3361
	 * mail_DeleteFolder - implementation of the DeleteFolder action of right click options on the tree
3362
	 *
3363
	 * @param _action
3364
	 * @param _senders - the representation of the tree leaf to be manipulated
3365
	 */
3366
	mail_DeleteFolder: function(_action,_senders) {
3367
		//action.id == 'delete'
3368
		//_senders.iface.id == target leaf / leaf to edit
3369
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
3370
		var OldFolderName = ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'');
3371
		var buttons = [
3372
			{text: this.egw.lang("Yes"), id: "delete", "class": "ui-priority-primary", "default": true},
3373
			{text: this.egw.lang("Cancel"), id:"cancel"}
3374
		];
3375
		et2_dialog.show_dialog(function(_button_id, _value) {
3376
			switch (_button_id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3377
			{
3378
				case "delete":
3379
					egw.json('mail.mail_ui.ajax_deleteFolder',[_senders[0].id])
3380
						.sendRequest(true);
3381
					return;
3382
				case "cancel":
3383
			}
3384
		},
3385
		this.egw.lang("Do you really want to DELETE Folder %1 ?",OldFolderName)+" "+(ftree.hasChildren(_senders[0].id)?this.egw.lang("All subfolders will be deleted too, and all messages in all affected folders will be lost"):this.egw.lang("All messages in the folder will be lost")),
3386
		this.egw.lang("DELETE Folder %1 ?",OldFolderName),
3387
		OldFolderName, buttons);
3388
	},
3389
3390
	/**
3391
	 * Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
3392
	 *
3393
	 * @param _event
3394
	 * @param _file_count
3395
	 * @param {string?} _path where the file is uploaded to, default current directory
3396
	 */
3397
	uploadForImport: function(_event, _file_count, _path)
3398
	{
3399
		// path is probably not needed when uploading for file; maybe it is when from vfs
3400
		if(typeof _path == 'undefined')
3401
		{
3402
			//_path = this.get_path();
3403
		}
3404
		if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
3405
		{
3406
			var widget = _event.data;
3407
//			var request = new egw_json_request('mail_ui::ajax_importMessage', ['upload', widget.getValue(), _path], this);
3408
//			widget.set_value('');
3409
//			request.sendRequest();//false, this._upload_callback, this);
3410
			this.et2_obj.submit();
3411
		}
3412
	},
3413
3414
	/**
3415
	 * Send names of uploaded files (again) to server, to process them: either copy to vfs or ask overwrite/rename
3416
	 *
3417
	 * @param {event object} _event
3418
	 * @param {string} _file_count
3419
	 * @param {string} _path [_path=current directory] Where the file is uploaded to.
3420
	 */
3421
	uploadForCompose: function(_event, _file_count, _path)
3422
	{
3423
		// path is probably not needed when uploading for file; maybe it is when from vfs
3424
		if(typeof _path == 'undefined')
3425
		{
3426
			//_path = this.get_path();
3427
		}
3428
		if (_file_count && !jQuery.isEmptyObject(_event.data.getValue()))
3429
		{
3430
			var widget = _event.data;
3431
			this.et2_obj.submit();
3432
		}
3433
	},
3434
3435
	/**
3436
	 * Visible attachment box in compose dialog as soon as the file starts to upload
3437
	 */
3438
	composeUploadStart: function ()
3439
	{
3440
		var boxAttachment = this.et2.getWidgetById('attachments');
3441
		if (boxAttachment)
3442
		{
3443
			var groupbox = boxAttachment.getParent();
3444
			if (groupbox) groupbox.set_disabled(false);
3445
		}
3446
		//Resize the compose dialog
3447
		var self = this;
3448
		setTimeout(function(){self.compose_resizeHandler();}, 100);
3449
		return true;
3450
	},
3451
3452
	/**
3453
	* Upload for import (VFS)
3454
	*
3455
	* @param {egw object} _egw
3456
	* @param {widget object} _widget
3457
	* @param {window object} _window
3458
	*/
3459
	vfsUploadForImport: function(_egw, _widget, _window) {
3460
		if (jQuery.isEmptyObject(_widget)) return;
3461
		if (!jQuery.isEmptyObject(_widget.getValue()))
3462
		{
3463
			this.et2_obj.submit();
3464
		}
3465
	},
3466
3467
	/**
3468
	* Upload for compose (VFS)
3469
	*
3470
	* @param {egw object} _egw
3471
	* @param {widget object} _widget
3472
	* @param {window object} _window
3473
	*/
3474
	vfsUploadForCompose: function(_egw, _widget, _window)
3475
	{
3476
		if (jQuery.isEmptyObject(_widget)) return;
3477
		if (!jQuery.isEmptyObject(_widget.getValue()))
3478
		{
3479
			this.et2_obj.submit();
3480
		}
3481
	},
3482
3483
	/**
3484
	* Submit on change (VFS)
3485
	*
3486
	* @param {egw object} _egw
3487
	* @param {widget object} _widget
3488
	*/
3489
	submitOnChange: function(_egw, _widget)
3490
	{
3491
		if (!jQuery.isEmptyObject(_widget))
3492
		{
3493
			if (typeof _widget.id !== 'undefined') var widgetId = _widget.id;
3494
			switch (widgetId)
0 ignored issues
show
Bug introduced by
The variable widgetId does not seem to be initialized in case typeof _widget.id !== "undefined" on line 3493 is false. Are you sure this can never be the case?
Loading history...
3495
			{
3496
				case 'mimeType':
3497
					this.et2_obj.submit();
3498
					break;
3499
				default:
3500
					if (!jQuery.isEmptyObject(_widget.getValue()))
3501
					{
3502
						this.et2_obj.submit();
3503
					}
3504
			}
3505
		}
3506
	},
3507
3508
	/**
3509
	 * Save as Draft (VFS)
3510
	 * -handel both actions save as draft and save as draft and print
3511
	 *
3512
	 * @param {egwAction} _egw_action
3513
	 * @param {array|string} _action string "autosaving", if that triggered the action
3514
	 */
3515
	saveAsDraft: function(_egw_action, _action)
3516
	{
3517
		//this.et2_obj.submit();
3518
		var content = this.et2.getArrayMgr('content').data;
3519
		var action = _action;
3520
		if (_egw_action && _action !== 'autosaving')
3521
		{
3522
			action = _egw_action.id;
3523
		}
3524
3525
		var widgets = ['from','to','cc','bcc','subject','folder','replyto','mailaccount',
3526
			'mail_htmltext', 'mail_plaintext', 'lastDrafted', 'filemode', 'expiration', 'password'];
3527
		var widget = {};
3528
		for (var index in widgets)
3529
		{
3530
			widget = this.et2.getWidgetById(widgets[index]);
3531
			if (widget)
3532
			{
3533
				content[widgets[index]] = widget.get_value();
3534
			}
3535
		}
3536
		var self = this;
3537
		if (content)
3538
		{
3539
			// if we compose an encrypted message, we have to get the encrypted content
3540
			if (this.mailvelope_editor)
3541
			{
3542
				this.mailvelope_editor.encrypt([]).then(function(_armored)
3543
				{
3544
					content['mail_plaintext'] = _armored;
3545
					self.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
3546
						self.savingDraft_response(_data,action);
3547
					}).sendRequest(true);
3548
				}, function(_err)
3549
				{
3550
					self.egw.message(_err.message, 'error');
3551
				});
3552
				return false;
3553
			}
3554
3555
			this.egw.json('mail.mail_compose.ajax_saveAsDraft',[content, action],function(_data){
3556
				self.savingDraft_response(_data,action);
3557
			}).sendRequest(true);
3558
		}
3559
	},
3560
3561
	/**
3562
	 * Set content of drafted message with new information sent back from server
3563
	 * This function would be used as callback of send request to ajax_saveAsDraft.
3564
	 *
3565
	 * @param {object} _responseData response data sent back from server by ajax_saveAsDraft function.
3566
	 *  the object conatins below items:
3567
	 *  -draftedId: new drafted id created by server
3568
	 *  -message: resault message
3569
	 *  -success: true if saving was successful otherwise false
3570
	 *  -draftfolder: Name of draft folder including its delimiter
3571
	 *
3572
	 * @param {string} _action action is the element which caused saving draft, it could be as such:
3573
	 *  -button[saveAsDraft]
3574
	 *  -button[saveAsDraftAndPrint]
3575
	 *  -autosaving
3576
	 */
3577
	savingDraft_response: function(_responseData, _action)
3578
	{
3579
		//Make sure there's a response from server otherwise shoot an error message
3580
		if (jQuery.isEmptyObject(_responseData))
3581
		{
3582
			this.egw.message('Could not saved the message. Because, the response from server failed.', 'error');
3583
			return false;
3584
		}
3585
3586
		if (_responseData.success)
3587
		{
3588
			var content = this.et2.getArrayMgr('content');
3589
			var lastDrafted = this.et2.getWidgetById('lastDrafted');
3590
			var folderTree = typeof opener.etemplate2.getByApplication('mail')[0] !='undefined'?
3591
								opener.etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('nm[foldertree]'): null;
3592
			var activeFolder = folderTree?folderTree.getSelectedNode():null;
3593
			if (content)
3594
			{
3595
				var prevDraftedId = content.data.lastDrafted;
3596
				content.data.lastDrafted = _responseData.draftedId;
3597
				this.et2.setArrayMgr('content', content);
3598
				lastDrafted.set_value(_responseData.draftedId);
3599
				if (folderTree && activeFolder)
3600
				{
3601
					if (typeof activeFolder.id !='undefined' && _responseData.draftfolder == activeFolder.id)
3602
					{
3603
						if (prevDraftedId)
3604
						{
3605
							opener.egw_refresh(_responseData.message,'mail', prevDraftedId, 'delete');
3606
						}
3607
						this.egw.refresh(_responseData.message,'mail',_responseData.draftedId);
3608
					}
3609
				}
3610
				switch (_action)
3611
				{
3612
					case 'button[saveAsDraftAndPrint]':
3613
						this.mail_compose_print('mail::'+_responseData.draftedId);
3614
						this.egw.message(_responseData.message);
3615
						break;
3616
					case 'autosaving':
3617
						//Any sort of thing if it's an autosaving action
3618
					default:
3619
						this.egw.message(_responseData.message);
3620
				}
3621
			}
3622
		}
3623
		else
3624
		{
3625
			this.egw.message(_responseData.message, 'error');
3626
		}
3627
	},
3628
3629
	/**
3630
	 * Focus handler for folder, address, reject textbox/taglist to automatic check associated radio button
3631
	 *
3632
	 * @param {event} _ev
3633
	 * @param {object} _widget taglist
3634
	 *
3635
	 */
3636
	sieve_focus_radioBtn: function(_ev, _widget)
3637
	{
3638
		_widget.getRoot().getWidgetById('action').set_value(_widget.id.replace(/^action_([^_]+)_text$/, '$1'));
3639
	},
3640
3641
	/**
3642
	 * Select all aliases
3643
	 *
3644
	 */
3645
	sieve_vac_all_aliases: function()
3646
	{
3647
		var aliases = [];
3648
		var tmp = [];
3649
		var addr = this.et2.getWidgetById('addresses');
3650
		var addresses = this.et2.getArrayMgr('sel_options').data.addresses;
3651
3652
		for(var id in addresses) aliases.push(id);
3653
		if (addr)
3654
		{
3655
			tmp = aliases.concat(addr.get_value());
3656
3657
			// returns de-duplicate items of an array
3658
			var deDuplicator = function (item,pos)
3659
			{
3660
				return tmp.indexOf(item) == pos;
3661
			};
3662
3663
			aliases = tmp.filter(deDuplicator);
3664
			addr.set_value(aliases);
3665
		}
3666
	},
3667
3668
	/**
3669
	 * Disable/Enable date widgets on vacation seive rules form when status is "by_date"
3670
	 *
3671
	 */
3672
	vacationFilterStatusChange: function()
3673
	{
3674
		var status = this.et2.getWidgetById('status');
3675
		var s_date = this.et2.getWidgetById('start_date');
3676
		var e_date = this.et2.getWidgetById('end_date');
3677
		var by_date_label = this.et2.getWidgetById('by_date_label');
3678
3679
		if (status && s_date && e_date && by_date_label)
3680
		{
3681
			s_date.set_disabled(status.get_value() != "by_date");
3682
			e_date.set_disabled(status.get_value() != "by_date");
3683
			by_date_label.set_disabled(status.get_value() != "by_date");
3684
		}
3685
	},
3686
3687
	/**
3688
	 * action - handling actions on sieve rules
3689
	 *
3690
	 * @param _type - action name
3691
	 * @param _selected - selected row from the sieve rule list
3692
	 */
3693
	action: function(_type, _selected)
3694
	{
3695
		var  actionData ;
3696
		var that = this;
3697
		var typeId = _type.id;
3698
		var linkData = '';
3699
		var ruleID = ((_selected[0].id.split("_").pop()) - 1); // subtract the row id from 1 because the first row id is reserved by grid header
3700
		if (_type)
3701
		{
3702
3703
			switch (_type.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
3704
			{
3705
				case 'delete':
3706
3707
					var callbackDeleteDialog = function (button_id)
3708
					{
3709
						if (button_id == et2_dialog.YES_BUTTON )
3710
						{
3711
							actionData = _type.parent.data.widget.getArrayMgr('content');
3712
							that._do_action(typeId, actionData['data'],ruleID);
3713
						}
3714
					};
3715
					et2_dialog.show_dialog(callbackDeleteDialog, this.egw.lang("Do you really want to DELETE this Rule"),this.egw.lang("Delete"), {},et2_dialog.BUTTONS_YES_CANCEL, et2_dialog.WARNING_MESSAGE);
3716
3717
					break;
3718
				case 'add'	:
3719
					linkData = "mail.mail_sieve.edit";
3720
					this.egw.open_link(linkData,'_blank',"600x480");
3721
					break;
3722
				case 'edit'	:
3723
					linkData = "mail.mail_sieve.edit&ruleID="+ruleID;
3724
					this.egw.open_link(linkData,'_blank',"600x480");
3725
					break;
3726
				case 'enable':
3727
					actionData = _type.parent.data.widget.getArrayMgr('content');
3728
					this._do_action(typeId,actionData['data'],ruleID);
3729
					break;
3730
				case 'disable':
3731
					actionData = _type.parent.data.widget.getArrayMgr('content');
3732
					this._do_action(typeId,actionData['data'],ruleID);
3733
					break;
3734
3735
			}
3736
		}
3737
3738
	},
3739
3740
	/**
3741
	* Send back sieve action result to server
3742
	*
3743
	* @param {string} _typeID action name
3744
	* @param {object} _data content
3745
	* @param {string} _selectedID selected row id
3746
	* @param {string} _msg message
3747
	*
3748
	*/
3749
	_do_action: function(_typeID, _data,_selectedID,_msg)
3750
	{
3751
		if (_typeID && _data)
3752
		{
3753
			var request = this.egw.json('mail.mail_sieve.ajax_action', [_typeID,_selectedID,_msg],null,null,true);
3754
			request.sendRequest();
3755
		}
3756
	},
3757
3758
	/**
3759
	* Send ajax request to server to refresh the sieve grid
3760
	*/
3761
	sieve_refresh: function()
3762
	{
3763
		this.et2._inst.submit();
3764
	},
3765
3766
	/**
3767
	 * Select the right combination of the rights for radio buttons from the selected common right
3768
	 *
3769
	 * @@param {jQuery event} event
3770
	 * @param {widget} widget common right selectBox
3771
	 *
3772
	 */
3773
	acl_common_rights_selector: function(event,widget)
3774
	{
3775
		var rowId = widget.id.replace(/[^0-9.]+/g, '');
3776
		var rights = [];
3777
3778
		switch (widget.get_value())
3779
		{
3780
			case 'custom':
3781
				break;
3782
			case 'aeiklprstwx':
3783
				rights = widget.get_value().replace(/[k,x,t,e]/g,"cd").split("");
3784
				break;
3785
			default:
3786
				rights = widget.get_value().split("");
3787
		}
3788
		if (rights.length > 0)
3789
		{
3790
			for (var i=0;i<this.aclRights.length;i++)
3791
			{
3792
				var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
3793
				rightsWidget.set_value((jQuery.inArray(this.aclRights[i],rights) != -1 )?true:false);
3794
			}
3795
		}
3796
	},
3797
3798
	/**
3799
	 *
3800
	 * Choose the right common right option for common ACL selecBox
3801
	 *
3802
	 * @param {jQuery event} event
3803
	 * @param {widget} widget radioButton rights
3804
	 *
3805
	 */
3806
	acl_common_rights: function(event, widget)
3807
	{
3808
	   var rowId = widget.id.replace(/[^0-9.]+/g, '');
3809
	   var aclCommonWidget = this.et2.getWidgetById(rowId + '[acl]');
3810
	   var rights = '';
3811
3812
	   for (var i=0;i<this.aclRights.length;i++)
3813
	   {
3814
		   var rightsWidget = this.et2.getWidgetById(rowId+'[acl_' + this.aclRights[i]+ ']');
3815
		   if (rightsWidget.get_value() == "true")
3816
			   rights += this.aclRights[i];
3817
3818
	   }
3819
3820
	   for (var i=0;i<this.aclCommonRights.length;i++)
3821
	   {
3822
		   if (rights.split("").sort().toString() == this.aclCommonRights[i].split("").sort().toString())
3823
			   rights = this.aclCommonRights[i];
3824
	   }
3825
	   if (jQuery.inArray(rights,this.aclCommonRights ) == -1 && rights !='lrswipcda')
3826
	   {
3827
		   aclCommonWidget.set_value('custom');
3828
	   }
3829
	   else if (rights =='lrswipcda')
3830
	   {
3831
           aclCommonWidget.set_value('aeiklprstwx');
3832
	   }
3833
	   else
3834
	   {
3835
		   aclCommonWidget.set_value(rights);
3836
	   }
3837
	},
3838
3839
	/**
3840
	 * Open seive filter list
3841
	 *
3842
	 * @param {action} _action
3843
	 * @param {sender} _senders
3844
	 *
3845
	 */
3846
	edit_sieve: function(_action, _senders)
3847
	{
3848
		var acc_id = parseInt(_senders[0].id);
3849
3850
		var url = this.egw.link('/index.php',{
3851
					'menuaction': 'mail.mail_sieve.index',
3852
					'acc_id': acc_id,
3853
					'ajax': 'true'
3854
		});
3855
3856
		// an ugly hack for idots to show up sieve rules not in an iframe
3857
		// but as new link, better to remove it after get rid of idots template
3858
		if (typeof window.framework == 'undefined')
3859
		{
3860
			this.egw.open_link(url);
3861
		}
3862
		else
3863
		{
3864
			this.loadIframe(url);
3865
		}
3866
	},
3867
3868
	/**
3869
	 * Load an url on an iframe
3870
	 *
3871
	 * @param {string} _url string egw url
3872
	 * @param {iframe widget} _iFrame an iframe to be set if non, extra_iframe is default
3873
	 *
3874
	 * @return {boolean} return TRUE if success, and FALSE if iframe not given
3875
	 */
3876
	loadIframe: function (_url, _iFrame)
3877
	{
3878
		var mailSplitter = this.et2.getWidgetById('splitter');
3879
		var quotaipercent = this.et2.getWidgetById('nm[quotainpercent]');
3880
		var iframe = _iFrame || this.et2.getWidgetById('extra_iframe');
3881
		if (typeof iframe != 'undefined' && iframe)
3882
		{
3883
			if (_url)
3884
			{
3885
				iframe.set_src(_url);
3886
			}
3887
			if (typeof mailSplitter != 'undefined' && mailSplitter && typeof quotaipercent != 'undefined')
3888
			{
3889
				mailSplitter.set_disabled(!!_url);
3890
				quotaipercent.set_disabled(!!_url);
3891
				iframe.set_disabled(!_url);
3892
			}
3893
			// extra_iframe used for showing up sieve rules
3894
			// need some special handling for mobile device
3895
			// as we wont have splitter, and also a fix for
3896
			// iframe with display none
3897
			if (iframe.id == "extra_iframe")
3898
			{
3899
				if (egwIsMobile())
3900
				{
3901
					var nm = this.et2.getWidgetById(this.nm_index);
3902
					nm.set_disabled(!!_url);
3903
					iframe.set_disabled(!_url);
3904
				}
3905
				// Set extra_iframe a class with height and width
3906
				// and position relative, seems iframe display none
3907
				// with 100% height/width covers mail tree and block
3908
				// therefore block the click handling
3909
				if (!iframe.disabled)
3910
				{
3911
					iframe.set_class('mail-index-extra-iframe');
3912
				}
3913
				else
3914
				{
3915
					iframe.set_class('');
3916
				}
3917
			}
3918
			return true;
3919
		}
3920
		return false;
3921
	},
3922
3923
	/**
3924
	 * Edit vacation message
3925
	 *
3926
	 * @param {action} _action
3927
	 * @param {sender} _senders
3928
	 */
3929
	edit_vacation: function(_action, _senders)
3930
	{
3931
		var acc_id = parseInt(_senders[0].id);
3932
		this.egw.open_link('mail.mail_sieve.editVacation&acc_id='+acc_id,'_blank','700x480');
3933
	},
3934
3935
	subscription_refresh: function(_data)
3936
	{
3937
		console.log(_data);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
3938
	},
3939
3940
	/**
3941
	 * Submit on apply button and save current tree state
3942
	 *
3943
	 * @param {type} _egw
3944
	 * @param {type} _widget
3945
	 * @returns {undefined}
3946
	 */
3947
	subscription_apply: function (_egw, _widget)
3948
	{
3949
		var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('foldertree');
3950
		if (tree)
3951
		{
3952
			tree.input._xfullXML = true;
3953
			this.subscription_treeLastState = tree.input.serializeTreeToJSON();
3954
		}
3955
		this.et2._inst.submit(_widget);
3956
	},
3957
3958
	/**
3959
	 * Show ajax-loader when the autoloading get started
3960
	 *
3961
	 * @param {type} _id item id
3962
	 * @param {type} _widget tree widget
3963
	 * @returns {Boolean}
3964
	 */
3965
	subscription_autoloadingStart: function (_id, _widget)
3966
	{
3967
		var node = _widget.input._globalIdStorageFind(_id);
3968
		if (node && typeof node.htmlNode != 'undefined')
3969
		{
3970
			var img = jQuery('img',node.htmlNode)[0];
3971
			img.src = egw.image('ajax-loader', 'admin');
3972
		}
3973
		return true;
3974
	},
3975
3976
	/**
3977
	 * Revert back the icon after autoloading is finished
3978
	 * @returns {Boolean}
3979
	 */
3980
	subscription_autoloadingEnd: function ()
3981
	{
3982
		return true;
3983
	},
3984
3985
	/**
3986
	 * Popup the subscription dialog
3987
	 *
3988
	 * @param {action} _action
3989
	 * @param {sender} _senders
3990
	 */
3991
	edit_subscribe: function (_action,_senders)
3992
	{
3993
		var acc_id = parseInt(_senders[0].id);
3994
		this.egw.open_link('mail.mail_ui.subscription&acc_id='+acc_id, '_blank', '720x500');
3995
	},
3996
3997
	/**
3998
	 * Subscribe selected unsubscribed folder
3999
	 *
4000
	 * @param {action} _action
4001
	 * @param {sender} _senders
4002
	 */
4003
	subscribe_folder: function(_action,_senders)
4004
	{
4005
		var mailbox = _senders[0].id.split('::');
4006
		var folder = mailbox[1], acc_id = mailbox[0];
4007
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
4008
		this.egw.message(this.egw.lang('Subscribe to Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
4009
		egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,true])
4010
			.sendRequest();
4011
	},
4012
4013
	/**
4014
	 * Unsubscribe selected subscribed folder
4015
	 *
4016
	 * @param {action} _action
4017
	 * @param {sender} _senders
4018
	 */
4019
	unsubscribe_folder: function(_action,_senders)
4020
	{
4021
		var mailbox = _senders[0].id.split('::');
4022
		var folder = mailbox[1], acc_id = mailbox[0];
4023
		var ftree = this.et2.getWidgetById(this.nm_index+'[foldertree]');
4024
		this.egw.message(this.egw.lang('Unsubscribe from Folder %1',ftree.getLabel(_senders[0].id).replace(this._unseen_regexp,'')));
4025
		egw.json('mail.mail_ui.ajax_foldersubscription',[acc_id,folder,false])
4026
			.sendRequest();
4027
	},
4028
4029
	/**
4030
	 * Onclick for node/foldername in subscription popup
4031
	 *
4032
	 * Used to (un)check node including all children
4033
	 *
4034
	 * @param {string} _id id of clicked node
4035
	 * @param {et2_tree} _widget reference to tree widget
4036
	 */
4037
	subscribe_onclick: function(_id, _widget)
4038
	{
4039
		_widget.setSubChecked(_id, "toggle");
4040
	},
4041
4042
	/**
4043
	 * Edit a folder acl for account(s)
4044
	 *
4045
	 * @param _action
4046
	 * @param _senders - the representation of the tree leaf to be manipulated
4047
	 */
4048
	edit_acl: function(_action, _senders)
4049
	{
4050
		var mailbox = _senders[0].id.split('::');
4051
		var folder = mailbox[1] || 'INBOX', acc_id = mailbox[0];
4052
		this.egw.open_link('mail.mail_acl.edit&mailbox='+ jQuery.base64Encode(folder)+'&acc_id='+acc_id, '_blank', '640x480');
4053
	},
4054
4055
	/**
4056
	 * Submit new selected folder back to server in order to read its acl's rights
4057
	 */
4058
	acl_folderChange: function ()
4059
	{
4060
		var mailbox = this.et2.getWidgetById('mailbox');
4061
4062
		if (mailbox)
4063
		{
4064
			if (mailbox.taglist.getValue().length > 0)
4065
			{
4066
				this.et2._inst.submit();
4067
			}
4068
		}
4069
	},
4070
4071
	/**
4072
	 * Edit a mail account
4073
	 *
4074
	 * @param _action
4075
	 * @param _senders - the representation of the tree leaf to be manipulated
4076
	 */
4077
	edit_account: function(_action, _senders)
4078
	{
4079
		var acc_id = parseInt(_senders[0].id);
4080
		this.egw.open_link('mail.mail_wizard.edit&acc_id='+acc_id, '_blank', '720x500');
4081
	},
4082
4083
	/**
4084
	 * Set expandable fields (Folder, Cc and Bcc) based on their content
4085
	 * - Only fields which have no content should get hidden
4086
	 */
4087
	compose_fieldExpander_init: function ()
4088
	{
4089
		var widgets = {
4090
			cc:{
4091
				widget:{},
4092
				jQClass: '.mailComposeJQueryCc'
4093
			},
4094
			bcc:{
4095
				widget:{},
4096
				jQClass: '.mailComposeJQueryBcc'
4097
			},
4098
			folder:{
4099
				widget:{},
4100
				jQClass: '.mailComposeJQueryFolder'
4101
			},
4102
			replyto:{
4103
				widget:{},
4104
				jQClass: '.mailComposeJQueryReplyto'
4105
			}};
4106
4107
		for(var widget in widgets)
4108
		{
4109
			var expanderBtn = widget + '_expander';
4110
			widgets[widget].widget = this.et2.getWidgetById(widget);
4111
			// Add expander button widget to the widgets object
4112
			widgets[expanderBtn] = {widget:this.et2.getWidgetById(expanderBtn)};
4113
4114
			if (typeof widgets[widget].widget != 'undefined'
4115
					&& typeof widgets[expanderBtn].widget != 'undefined'
4116
					&& widgets[widget].widget.get_value().length == 0)
4117
			{
4118
				widgets[expanderBtn].widget.set_disabled(false);
4119
				jQuery(widgets[widget].jQClass).hide();
4120
			}
4121
		}
4122
	},
4123
4124
	/**
4125
	 * Control textArea size based on available free space at the bottom
4126
	 *
4127
	 */
4128
	compose_resizeHandler: function()
4129
	{
4130
		// Do not resize compose dialog if it's running on mobile device
4131
		// in this case user would be able to edit mail body by scrolling down,
4132
		// which is more convenient on small devices. Also resize mailbody with
4133
		// ckeditor may causes performance regression, especially on devices with
4134
		// very limited resources and slow proccessor.
4135
		if (egwIsMobile()) return false;
4136
4137
		try {
4138
			var bodyH = egw_getWindowInnerHeight();
4139
			var textArea = this.et2.getWidgetById('mail_plaintext');
4140
			var $headerSec = jQuery('.mailComposeHeaderSection');
4141
			var attachments = this.et2.getWidgetById('attachments');
4142
			var content = this.et2.getArrayMgr('content').data;
4143
4144
			// @var arrbitary int represents px
4145
			// Visible height of attachment progress
4146
			var prgV_H = 150;
4147
4148
			// @var arrbitary int represents px
4149
			// Visible height of attchements list
4150
			var attchV_H = 68;
4151
4152
			if (typeof textArea != 'undefined' && textArea != null)
4153
			{
4154
				if (textArea.getParent().disabled)
4155
				{
4156
					textArea = this.et2.getWidgetById('mail_htmltext');
4157
				}
4158
				// Tolerate values base on plain text or html, in order to calculate freespaces
4159
				var textAreaDelta = textArea.id == "mail_htmltext"?20:40;
4160
4161
				// while attachments are in progress take progress visiblity into account
4162
				// otherwise the attachment progress is finished and consider attachments list
4163
				var delta = (attachments.table.find('li').length>0 && attachments.table.height() > 0)? prgV_H: (content.attachments? attchV_H: textAreaDelta);
4164
4165
				var bodySize = (bodyH  - Math.round($headerSec.height() + $headerSec.offset().top) - delta);
4166
4167
				if (textArea.id != "mail_htmltext")
4168
				{
4169
					textArea.getParent().set_height(bodySize);
4170
					textArea.set_height(bodySize);
4171
				}
4172
				else if (typeof textArea != 'undefined' && textArea.id == 'mail_htmltext')
4173
				{
4174
					textArea.ckeditor.resize('100%', bodySize);
4175
				}
4176
				else
4177
				{
4178
					textArea.set_height(bodySize - 90);
4179
				}
4180
			}
4181
		}
4182
		catch(e) {
4183
			// ignore errors causing compose to load twice
4184
		}
4185
	},
4186
4187
	/**
4188
	 * Display Folder,Cc or Bcc fields in compose popup
4189
	 *
4190
	 * @param {jQuery event} event
4191
	 * @param {widget object} widget clicked label (Folder, Cc or Bcc) from compose popup
4192
	 *
4193
	 */
4194
	compose_fieldExpander: function(event,widget)
4195
	{
4196
		var expWidgets = {cc:{},bcc:{},folder:{},replyto:{}};
4197
		for (var name in expWidgets)
4198
		{
4199
			expWidgets[name] = this.et2.getWidgetById(name+'_expander');
4200
		}
4201
4202
		if (typeof widget !='undefined')
4203
		{
4204
			switch (widget.id)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4205
			{
4206
				case 'cc_expander':
4207
					jQuery(".mailComposeJQueryCc").show();
4208
					if (typeof expWidgets.cc !='undefined')
4209
					{
4210
						expWidgets.cc.set_disabled(true);
4211
					}
4212
					break;
4213
				case 'bcc_expander':
4214
					jQuery(".mailComposeJQueryBcc").show();
4215
					if (typeof expWidgets.bcc !='undefined')
4216
					{
4217
						expWidgets.bcc.set_disabled(true);
4218
					}
4219
					break;
4220
				case 'folder_expander':
4221
					jQuery(".mailComposeJQueryFolder").show();
4222
					if (typeof expWidgets.folder !='undefined')
4223
					{
4224
						expWidgets.folder.set_disabled(true);
4225
					}
4226
					break;
4227
				case 'replyto_expander':
4228
					jQuery(".mailComposeJQueryReplyto").show();
4229
					if (typeof expWidgets.replyto !='undefined')
4230
					{
4231
						expWidgets.replyto.set_disabled(true);
4232
					}
4233
					break;
4234
			}
4235
		}
4236
		else if (typeof widget == "undefined")
4237
		{
4238
			var widgets = {cc:{},bcc:{},folder:{},replyto:{}};
4239
4240
			for(var widget in widgets)
4241
			{
4242
				widgets[widget] = this.et2.getWidgetById(widget);
4243
4244
				if (widgets[widget].get_value().length)
4245
				{
4246
					switch (widget)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4247
					{
4248
						case 'cc':
4249
							jQuery(".mailComposeJQueryCc").show();
4250
							if (typeof expWidgets.cc != 'undefiend')
4251
							{
4252
								expWidgets.cc.set_disabled(true);
4253
							}
4254
							break;
4255
						case 'bcc':
4256
							jQuery(".mailComposeJQueryBcc").show();
4257
							if (typeof expWidgets.bcc != 'undefiend')
4258
							{
4259
								expWidgets.bcc.set_disabled(true);
4260
							}
4261
							break;
4262
						case 'folder':
4263
							jQuery(".mailComposeJQueryFolder").show();
4264
							if (typeof expWidgets.folder != 'undefiend')
4265
							{
4266
								expWidgets.folder.set_disabled(true);
4267
							}
4268
							break;
4269
						case 'replyto':
4270
							jQuery(".mailComposeJQueryReplyto").show();
4271
							if (typeof expWidgets.replyto != 'undefiend')
4272
							{
4273
								expWidgets.replyto.set_disabled(true);
4274
							}
4275
							break;
4276
					}
4277
				}
4278
			}
4279
		}
4280
		this.compose_resizeHandler();
4281
	},
4282
4283
	/**
4284
	 * Lock tree so it does NOT receive any more mouse-clicks
4285
	 */
4286
	lock_tree: function()
4287
	{
4288
		if (!document.getElementById('mail_folder_lock_div'))
4289
		{
4290
			var parent = jQuery('#mail-index_nm\\[foldertree\\]');
4291
			var lock_div = jQuery(document.createElement('div'));
4292
			lock_div.attr('id', 'mail_folder_lock_div')
4293
				.addClass('mail_folder_lock');
4294
			parent.prepend(lock_div);
4295
		}
4296
	},
4297
4298
	/**
4299
	 * Unlock tree so it receives again mouse-clicks after calling lock_tree()
4300
	 */
4301
	unlock_tree: function()
4302
	{
4303
		jQuery('#mail_folder_lock_div').remove();
4304
	},
4305
4306
	/**
4307
	 * Called when tree opens up an account or folder
4308
	 *
4309
	 * @param {String} _id account-id[::folder-name]
4310
	 * @param {et2_widget_tree} _widget
4311
	 * @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
4312
	 */
4313
	openstart_tree: function(_id, _widget, _hasChildren)
4314
	{
4315
		if (_id.indexOf('::') == -1 &&	// it's an account, not a folder in an account
4316
			!_hasChildren)
4317
		{
4318
			this.lock_tree();
4319
		}
4320
		return true;	// allow opening of node
4321
	},
4322
4323
	/**
4324
	 * Called when tree opens up an account or folder
4325
	 *
4326
	 * @param {String} _id account-id[::folder-name]
4327
	 * @param {et2_widget_tree} _widget
4328
	 * @param {Number} _hasChildren 0 - item has no child nodes, -1 - item is closed, 1 - item is opened
4329
	 */
4330
	openend_tree: function(_id, _widget, _hasChildren)
4331
	{
4332
		if (_id.indexOf('::') == -1 &&	// it's an account, not a folder in an account
4333
			_hasChildren == 1)
4334
		{
4335
			this.unlock_tree();
4336
		}
4337
	},
4338
4339
	/**
4340
	 * Print a mail from list
4341
4342
	 * @param _action
4343
	 * @param _senders - the representation of the tree leaf to be manipulated
4344
	 */
4345
	mail_print: function(_action, _senders)
4346
	{
4347
		var currentTemp = this.et2._inst.name;
4348
4349
		switch (currentTemp)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4350
		{
4351
			case 'mail.index':
4352
				this.mail_prev_print(_action, _senders);
4353
				break;
4354
			case 'mail.display':
4355
				this.mail_display_print();
4356
		}
4357
4358
	},
4359
4360
	/**
4361
	 * Print a mail from compose
4362
	 * @param {stirng} _id id of new draft
4363
	 */
4364
	mail_compose_print:function (_id)
4365
	{
4366
		this.egw.open(_id,'mail','view','&print='+_id+'&mode=print');
4367
	},
4368
4369
	/**
4370
	 * Bind special handler on print media.
4371
	 * -FF and IE have onafterprint event, and as Chrome does not have that event we bind afterprint function to onFocus
4372
	 */
4373
	print_for_compose: function()
4374
	{
4375
		var afterprint = function (){
4376
			egw(window).close();
4377
		};
4378
4379
		if (!window.onafterprint)
4380
		{
4381
			// For browsers which does not support onafterprint event, eg. Chrome
4382
			setTimeout(function() {
4383
				egw(window).close();
4384
			}, 2000);
4385
		}
4386
		else
4387
		{
4388
			window.onafterprint = afterprint;
4389
		}
4390
	},
4391
4392
	/**
4393
	 * Prepare display dialog for printing
4394
	 * copies iframe content to a DIV, as iframe causes
4395
	 * trouble for multipage printing
4396
	 * @param {jQuery object} _iframe mail body iframe
4397
	 * @returns {undefined}
4398
	 */
4399
	mail_prepare_print: function(_iframe)
4400
	{
4401
		var $mainIframe = _iframe || jQuery('#mail-display_mailDisplayBodySrc');
4402
		var tmpPrintDiv = jQuery('#tempPrintDiv');
4403
4404
		if (tmpPrintDiv.length == 0 && tmpPrintDiv.children())
4405
		{
4406
			tmpPrintDiv = jQuery(document.createElement('div'))
4407
							.attr('id', 'tempPrintDiv')
4408
							.addClass('tmpPrintDiv');
4409
			var notAttached = true;
4410
		}
4411
4412
		if ($mainIframe)
4413
		{
4414
			tmpPrintDiv[0].innerHTML = $mainIframe.contents().find('body').html();
4415
		}
4416
		// Attach the element to the DOM after maniupulation
4417
		if (notAttached) $mainIframe.after(tmpPrintDiv);
4418
		tmpPrintDiv.find('#divAppboxHeader').remove();
4419
4420
	},
4421
4422
	/**
4423
	 * Print a mail from Display
4424
	 */
4425
	mail_display_print: function ()
4426
	{
4427
		this.egw.message('Printing....');
4428
4429
		// Make sure the print happens after the content is loaded. Seems Firefox and IE can't handle timing for print command correctly
4430
		setTimeout(function(){
4431
			egw(window).window.print();
4432
		},100);
4433
	},
4434
4435
	/**
4436
	 * Print a mail from list
4437
	 *
4438
	 * @param {Object} _action
4439
	 * @param {Object} _elems
4440
	 *
4441
	 */
4442
	mail_prev_print: function (_action, _elems)
4443
	{
4444
		this.mail_open(_action, _elems, 'print');
4445
	},
4446
4447
	/**
4448
	 * Print a mail from list
4449
	 *
4450
	 * @param {egw object} _egw
4451
	 * @param {widget object} _widget mail account selectbox
4452
	 *
4453
	 */
4454
	vacation_change_account: function (_egw, _widget)
4455
	{
4456
		_widget.getInstanceManager().submit();
4457
	},
4458
4459
	/**
4460
	 * OnChange callback for recipients:
4461
	 * - make them draggable
4462
	 * - check if we have keys for recipients, if we compose an encrypted mail
4463
	 **/
4464
	recipients_onchange: function()
4465
	{
4466
		// if we compose an encrypted mail, check if we have keys for new recipient
4467
		if (this.mailvelope_editor)
4468
		{
4469
			var self = this;
4470
			this.mailvelopeGetCheckRecipients().catch(function(_err)
4471
			{
4472
				self.egw.message(_err.message, 'error');
4473
			});
4474
		}
4475
		this.set_dragging_dndCompose();
4476
	},
4477
4478
	/**
4479
	 * Make recipients draggable
4480
	 */
4481
	set_dragging_dndCompose: function ()
4482
	{
4483
		var zIndex = 100;
4484
		var dragItems = jQuery('div.ms-sel-item:not(div.ui-draggable)');
4485
		dragItems.each(function(i,item){
4486
				var $isErr = jQuery(item).find('.ui-state-error');
4487
				if ($isErr.length > 0)
4488
				{
4489
					delete dragItems.splice(i,1);
4490
				}
4491
			});
4492
		if (dragItems.length > 0)
4493
		{
4494
			dragItems.draggable({
4495
				appendTo:'body',
4496
				//Performance wise better to not add ui-draggable class to items since we are not using that class
4497
				containment:'document',
4498
				distance: 0,
4499
				cursor:'move',
4500
				cursorAt:{left:2},
4501
				//cancel dragging on close button to avoid conflict with close action
4502
				cancel:'.ms-close-btn',
4503
				delay: '300',
4504
				/**
4505
				 * function to act on draggable item on revert's event
4506
				 * @returns {Boolean} return true
4507
				 */
4508
				revert: function (){
4509
					this.parent().find('.ms-sel-item').css('position','relative');
4510
					var $input = this.parent().children('input');
4511
					// Make sure input field not getting into second line after revert
4512
					$input.width($input.width()-10);
4513
					return true;
4514
				},
4515
				/**
4516
				 * function to act as draggable starts dragging
4517
				 *
4518
				 * @param {type} event
4519
				 * @param {type} ui
4520
				 */
4521
				start:function(event, ui)
4522
				{
4523
					var dragItem = jQuery(this);
4524
					if (event.ctrlKey || event.metaKey)
4525
					{
4526
						dragItem.addClass('mailCompose_copyEmail')
4527
								.css('cursor','copy');
4528
					}
4529
					dragItem.css ('z-index',zIndex++);
4530
					dragItem.css('position','absolute');
4531
				},
4532
				/**
4533
				 *
4534
				 * @param {type} event
4535
				 * @param {type} ui
4536
				 */
4537
				create:function(event,ui)
4538
				{
4539
					jQuery(this).css('css','move');
4540
				}
4541
			}).draggable('disable');
4542
			window.setTimeout(function(){
4543
4544
				if(dragItems && dragItems.data() && typeof dragItems.data()['uiDraggable'] !== 'undefined') dragItems.draggable('enable');
4545
			},100);
4546
		}
4547
4548
	},
4549
4550
	/**
4551
	 * Initialize dropping targets for draggable emails
4552
	 * -
4553
	 */
4554
	init_dndCompose: function ()
4555
	{
4556
4557
		var self = this;
4558
		var emailTags = jQuery('#mail-compose_to,#mail-compose_cc,#mail-compose_bcc');
4559
		//Call to make new items draggable
4560
		emailTags.hover(function(){
4561
			self.set_dragging_dndCompose();
4562
		});
4563
		//Make used email-tag list widgets in mail compose droppable
4564
		emailTags.droppable({
4565
			accept:'.ms-sel-item',
4566
4567
			/**
4568
			 * Run after a draggable email item dropped over one of the email-taglists
4569
			 * -Set the dropped item to the dropped current target widget
4570
			 *
4571
			 * @param {type} event
4572
			 * @param {type} ui
4573
			 */
4574
			drop:function (event, ui)
4575
			{
4576
				var widget = self.et2.getWidgetById(this.getAttribute('name'));
4577
				var emails, distLists = [];
4578
				var fromWidget = {};
4579
4580
				var parentWidgetDOM = ui.draggable.parentsUntil('div[id^="mail-compoe_"]','.ui-droppable');
4581
				if (parentWidgetDOM != 'undefined' && parentWidgetDOM.length > 0)
4582
				{
4583
					fromWidget = self.et2.getWidgetById(parentWidgetDOM.attr('name'));
4584
				}
4585
4586
				var draggedValue = ui.draggable.text();
4587
4588
				// index of draggable item in selection list
4589
				var dValueKey = draggedValue;
4590
4591
				var distItem = ui.draggable.find('.mailinglist');
4592
				if (distItem.length>0)
4593
				{
4594
					var distItemId = parseInt(distItem.attr('data'));
4595
					if (distItemId)
4596
					{
4597
						var fromDistLists = resolveDistList(fromWidget);
4598
						for (var i=0;i<fromDistLists.length;i++)
4599
						{
4600
							if (distItemId == fromDistLists[i]['id'])
4601
							{
4602
								draggedValue = fromDistLists[i];
4603
								// dist list item index
4604
								dValueKey = fromDistLists[i]['id'];
4605
							}
4606
						}
4607
					}
4608
				}
4609
4610
				if (typeof widget != 'undefined')
4611
				{
4612
					emails = widget.get_value();
4613
					if (emails) emails = emails.concat([draggedValue]);
4614
4615
					// Resolve the dist list and normal emails
4616
					distLists = resolveDistList(widget, emails);
4617
4618
					// Add normal emails
4619
					if (emails) widget.set_value(emails);
4620
4621
					// check if there's any dist list to be added
4622
					if (distLists.length>0) widget.taglist.addToSelection(distLists);
4623
4624
					if (!jQuery.isEmptyObject(fromWidget)
4625
							&& !(ui.draggable.attr('class').search('mailCompose_copyEmail') > -1))
4626
					{
4627
						if (widget.node != fromWidget.node && !_removeDragged(fromWidget, dValueKey))
4628
						{
4629
							//Not successful remove, returns the item to its origin
4630
							jQuery(ui.draggable).draggable('option','revert',true);
4631
						}
4632
					}
4633
					else
4634
					{
4635
						ui.draggable
4636
								.removeClass('mailCompose_copyEmail')
4637
								.css('cursor','move');
4638
					}
4639
4640
					var dragItems = jQuery('div.ms-sel-item');
4641
					dragItems.each(function(i,item){
4642
						var $isErr = jQuery(item).find('.ui-state-error');
4643
						if ($isErr.length > 0)
4644
						{
4645
							delete dragItems.splice(i,1);
4646
						}
4647
					});
4648
				}
4649
			}
4650
		});
4651
4652
		/**
4653
		 * Remove dragged item from the widget which the item was dragged
4654
		 *
4655
		 * @param {type} _widget
4656
		 * @param {type} _value
4657
		 * @return {boolean} true if successul | false unsuccessul
4658
		 */
4659
		var _removeDragged = function (_widget, _value)
4660
		{
4661
			if (_widget && _value)
4662
			{
4663
				var emails = _widget.get_value();
4664
				var itemIndex = emails.indexOf(_value);
4665
				var dist = [];
4666
				if (itemIndex > -1)
4667
				{
4668
					emails.splice(itemIndex,1);
4669
					// Resolve the dist list and normal emails
4670
					var dist = resolveDistList(_widget, emails);
4671
4672
					// Add normal emails
4673
					_widget.set_value(emails);
4674
4675
					//check if there's any dist list to be added
4676
					if (dist)
4677
					{
4678
						for(var i=0;i<dist.length;i++)
4679
						{
4680
							if (dist[i]['id'] == _value) dist.splice(i,1);
4681
						}
4682
						_widget.taglist.addToSelection(dist);
4683
					}
4684
				}
4685
				else
4686
				{
4687
					return false;
4688
				}
4689
			}
4690
			return true;
4691
		};
4692
4693
		/**
4694
		 * Resolve taglist widget which has distribution list
4695
		 *
4696
		 * @param {type} _widget
4697
		 * @param {type} _emails
4698
		 * @returns {Array} returns an array of distribution lists in selected widget
4699
		 */
4700
		var resolveDistList = function (_widget, _emails)
4701
		{
4702
			var list = [];
4703
			var selectedList = _widget.taglist.getSelection();
4704
			// Make a list of distribution list from the selection
4705
			for (var i=0;i<selectedList.length;i++)
4706
			{
4707
				if (!isNaN(selectedList[i]['id']) && selectedList[i]['class'] === 'mailinglist')
4708
				{
4709
					list.push(selectedList[i]);
4710
				}
4711
			}
4712
4713
			// Remove dist list from emails list
4714
			for(var key in _emails)
4715
			{
4716
				if (!isNaN(_emails[key]))
4717
				{
4718
					_emails.splice(key,1);
4719
				}
4720
			}
4721
			// returns distlist
4722
			return list;
4723
		};
4724
	},
4725
4726
	/**
4727
	* Check sharing mode and disable not available options
4728
	*
4729
	* @param {DOMNode} _node
4730
	* @param {et2_widget} _widget
4731
	*/
4732
	check_sharing_filemode: function(_node, _widget)
4733
	{
4734
		if (!_widget) _widget = this.et2.getWidgetById('filemode');
4735
4736
		var extended_settings = _widget.get_value() != 'attach' && this.egw.app('stylite');
4737
		this.et2.getWidgetById('expiration').set_readonly(!extended_settings);
4738
		this.et2.getWidgetById('password').set_readonly(!extended_settings);
4739
4740
		if (_widget.get_value() == 'share_rw' && !this.egw.app('stylite'))
4741
		{
4742
			this.egw.message(this.egw.lang('Writable sharing requires EPL version!'), 'info');
4743
			_widget.set_value('share_ro');
4744
		}
4745
	},
4746
4747
	/**
4748
	 * Write / update compose window title with subject
4749
	 *
4750
	 * @param {DOMNode} _node
4751
	 * @param {et2_widget} _widget
4752
	 */
4753
	subject2title: function(_node, _widget)
4754
	{
4755
		if (!_widget) _widget = this.et2.getWidgetById('subject');
4756
4757
		if (_widget && _widget.get_value())
4758
		{
4759
			document.title = _widget.get_value();
4760
		}
4761
	},
4762
4763
	/**
4764
	 * Clear intervals stored in W_INTERVALS which assigned to window
4765
	 */
4766
	clearIntevals: function ()
4767
	{
4768
		for(var i=0;i<this.W_INTERVALS.length;i++)
4769
		{
4770
			clearInterval(this.W_INTERVALS[i]);
4771
			delete this.W_INTERVALS[i];
4772
		}
4773
	},
4774
4775
	/**
4776
	 * Window title getter function in order to set the window title
4777
	 *
4778
	 * @returns {string|undefined} window title
4779
	 */
4780
	getWindowTitle: function ()
4781
	{
4782
		var widget = {};
4783
		switch(this.et2._inst.name)
0 ignored issues
show
Coding Style introduced by
As per coding-style, switch statements should have a default case.
Loading history...
4784
		{
4785
			case 'mail.display':
4786
				widget = this.et2.getWidgetById('mail_displaysubject');
4787
				if (widget) return widget.options.value;
4788
				break;
4789
			case 'mail.compose':
4790
				widget = this.et2.getWidgetById('subject');
4791
				if (widget) return widget.get_value();
4792
				break;
4793
		}
4794
		return undefined;
4795
	},
4796
4797
	/**
4798
	 *
4799
	 * @returns {undefined}
4800
	 */
4801
	prepareMailvelopePrint: function()
4802
	{
4803
		var tempPrint = jQuery('div#tempPrintDiv');
4804
		var mailvelopeTopContainer = jQuery('div.mailDisplayContainer');
4805
		var originFrame = jQuery('#mail-display_mailDisplayBodySrc');
4806
		var iframe = jQuery(this.mailvelope_iframe_selector);
4807
4808
		if (tempPrint.length >0)
4809
		{
4810
			// Mailvelope iframe height is approximately equal to the height of encrypted origin message
4811
			// we add an arbitary plus pixels to make sure it's covering the full content in print view and
4812
			// it is not getting acrollbar in normal view
4813
			// @TODO: after Mailvelope plugin provides a hieght value, we can replace the height with an accurate value
4814
			iframe.addClass('mailvelopeIframe').height(originFrame[0].contentWindow.document.body.scrollHeight + 400);
4815
			tempPrint.hide();
4816
			mailvelopeTopContainer.addClass('mailvelopeTopContainer');
4817
		}
4818
	},
4819
4820
	/**
4821
	 * Mailvelope (clientside PGP) integration:
4822
	 * - detect Mailvelope plugin and open "egroupware" keyring (app_base.mailvelopeAvailable and _mailvelopeOpenKeyring)
4823
	 * - display and preview of encrypted messages (mailvelopeDisplay)
4824
	 * - button to toggle between regular and encrypted mail (togglePgpEncrypt)
4825
	 * - compose encrypted messages (mailvelopeCompose, compose_submitAction)
4826
	 * - fix autosave and save as draft to store encrypted content (saveAsDraft)
4827
	 * - fix inline reply to encrypted message to clientside decrypt message and add signature (mailvelopeCompose)
4828
	 */
4829
4830
	/**
4831
	 * Called on load of preview or display iframe, if mailvelope is available
4832
	 *
4833
	 * @param {Keyring} _keyring Mailvelope keyring to use
4834
	 * @ToDo signatures
4835
	 */
4836
	mailvelopeDisplay: function(_keyring)
4837
	{
4838
		var self = this;
4839
		var mailvelope = window.mailvelope;
4840
		var iframe = jQuery('iframe#mail-display_mailDisplayBodySrc,iframe#mail-index_messageIFRAME');
4841
		var armored = iframe.contents().find('td.td_display > pre').text().trim();
4842
4843
		if (armored == "" || armored.indexOf(this.begin_pgp_message) === -1) return;
4844
4845
		var container = iframe.parent()[0];
4846
		var container_selector = container.id ? '#'+container.id : 'div.mailDisplayContainer';
4847
4848
		options = {
4849
			showExternalContent: this.egw.preference('allowExternalIMGs') == 1	// "1", or "0", undefined --> true or false
4850
		};
4851
		// get sender address, so Mailvelope can check signature
4852
		var from_widget = this.et2.getWidgetById('FROM_0') || this.et2.getWidgetById('previewFromAddress');
4853
		if (from_widget && from_widget.value)
4854
		{
4855
			options.senderAddress = from_widget.value.replace(/^.*<([^<>]+)>$/, '$1');
4856
		}
4857
		mailvelope.createDisplayContainer(container_selector, armored, _keyring, options).then(function()
4858
		{
4859
			// hide our iframe to give space for mailvelope iframe with encrypted content
4860
			iframe.hide();
4861
			self.prepareMailvelopePrint();
4862
		},
4863
		function(_err)
4864
		{
4865
			self.egw.message(_err.message, 'error');
4866
		});
4867
	},
4868
4869
	/**
4870
	 * Editor object of active compose
4871
	 *
4872
	 * @var {Editor}
4873
	 */
4874
	mailvelope_editor: undefined,
4875
4876
	/**
4877
	 * Called on compose, if mailvelope is available
4878
	 *
4879
	 * @param {Keyring} _keyring Mailvelope keyring to use
4880
	 */
4881
	mailvelopeCompose: function(_keyring)
4882
	{
4883
		delete this.mailvelope_editor;
4884
4885
		// currently Mailvelope only supports plain-text, to this is unnecessary
4886
		var mimeType = this.et2.getWidgetById('mimeType');
4887
		var is_html = mimeType.get_value();
4888
		var container = is_html ? '.mailComposeHtmlContainer' : '.mailComposeTextContainer';
4889
		var editor = this.et2.getWidgetById(is_html ? 'mail_htmltext' : 'mail_plaintext');
4890
		var options = { predefinedText: editor.get_value() };
4891
4892
		// check if we have some sort of reply to an encrypted message
4893
		// --> parse header, encrypted mail to quote and signature so Mailvelope understands it
4894
		var start_pgp = options.predefinedText.indexOf(this.begin_pgp_message);
4895
		if (start_pgp != -1)
4896
		{
4897
			var end_pgp = options.predefinedText.indexOf(this.end_pgp_message);
4898
			if (end_pgp != -1)
4899
			{
4900
				options = {
4901
					quotedMailHeader: options.predefinedText.slice(0, start_pgp).replace(/> /mg, '').trim()+"\n",
4902
					quotedMail: options.predefinedText.slice(start_pgp, end_pgp+this.end_pgp_message.length+1).replace(/> /mg, ''),
4903
					quotedMailIndent: start_pgp != 0,
4904
					predefinedText: options.predefinedText.slice(end_pgp+this.end_pgp_message.length+1).replace(/^> \s*/m,''),
4905
					signMsg: true	// for now (no UI) always sign, when we encrypt
4906
				};
4907
				// set encrypted checkbox, if not already set
4908
				var composeToolbar = this.et2.getWidgetById('composeToolbar');
4909
				if (!composeToolbar.checkbox('pgp'))
4910
				{
4911
					composeToolbar.checkbox('pgp',true);
4912
				}
4913
			}
4914
		}
4915
4916
		var self = this;
4917
		mailvelope.createEditorContainer(container, _keyring, options).then(function(_editor)
4918
		{
4919
			self.mailvelope_editor = _editor;
4920
			editor.set_disabled(true);
4921
			mimeType.set_readonly(true);
4922
		},
4923
		function(_err)
4924
		{
4925
			self.egw.message(_err.message, 'error');
4926
		});
4927
	},
4928
4929
	/**
4930
	 * Switch sending PGP encrypted mail on and off
4931
	 *
4932
	 * @param {object} _action toolbar action
4933
	 */
4934
	togglePgpEncrypt: function (_action)
4935
	{
4936
		var self = this;
4937
		if (_action.checked)
4938
		{
4939
			if (typeof mailvelope == 'undefined')
4940
			{
4941
				this.mailvelopeInstallationOffer();
4942
				// switch encrypt button off again
4943
				this.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
4944
				jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
4945
				return;
4946
			}
4947
			// check if we have keys for all recipents, before switching
4948
			this.mailvelopeGetCheckRecipients().then(function(_recipients)
4949
			{
4950
				var mimeType = self.et2.getWidgetById('mimeType');
4951
				// currently Mailvelope only supports plain-text, switch to it if necessary
4952
				if (mimeType.get_value())
4953
				{
4954
					mimeType.set_value(false);
4955
					self.et2._inst.submit();
4956
					return;	// ToDo: do that without reload
4957
				}
4958
				self.mailvelopeOpenKeyring().then(function(_keyring)
4959
				{
4960
					self.mailvelopeCompose(_keyring);
4961
				});
4962
			})
4963
			.catch(function(_err)
4964
			{
4965
				self.egw.message(_err.message, 'error');
4966
				self.et2.getWidgetById('composeToolbar')._actionManager.getActionById('pgp').set_checked(false);
4967
				jQuery('button#composeToolbar-pgp').toggleClass('toolbar_toggled');
4968
				return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
4969
			});
4970
		}
4971
		else
4972
		{
4973
			// switch Mailvelop off again, but warn user he will loose his content
4974
			et2_dialog.show_dialog(function (_button_id)
4975
			{
4976
				if (_button_id == et2_dialog.YES_BUTTON )
4977
				{
4978
					self.et2.getWidgetById('mimeType').set_readonly(false);
4979
					self.et2.getWidgetById('mail_plaintext').set_disabled(false);
4980
					jQuery(self.mailvelope_iframe_selector).remove();
4981
				}
4982
				else
4983
				{
4984
					self.et2.getWidgetById('composeToolbar').checkbox('pgp',true);
4985
				}
4986
			},
4987
			this.egw.lang('You will loose current message body, unless you save it to your clipboard!'),
4988
			this.egw.lang('Switch off encryption?'),
4989
			{}, et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, this.egw);
4990
		}
4991
	},
4992
4993
	/**
4994
	 * Check if we have a key for all recipients
4995
	 *
4996
	 * @returns {Promise.<Array, Error>} Array of recipients or Error with recipients without key
4997
	 */
4998
	mailvelopeGetCheckRecipients: function()
4999
	{
5000
		// collect all recipients
5001
		var recipients = this.et2.getWidgetById('to').get_value();
5002
		recipients = recipients.concat(this.et2.getWidgetById('cc').get_value());
5003
		recipients = recipients.concat(this.et2.getWidgetById('bcc').get_value());
5004
5005
		return this._super.call(this, recipients);
5006
	},
5007
5008
	/**
5009
	 * Set the relevant widget to toolbar actions and submit
5010
	 *
5011
	 * @param {object|boolean} _action toolbar action or boolean value to stop extra call on
5012
	 * compose_integrated_submit
5013
	 */
5014
	compose_submitAction: function (_action)
5015
	{
5016
		if (this.compose_integrate_submit() && _action) return false;
5017
5018
		if (this.mailvelope_editor)
5019
		{
5020
			var self = this;
5021
			this.mailvelopeGetCheckRecipients().then(function(_recipients)
5022
			{
5023
				return self.mailvelope_editor.encrypt(_recipients);
5024
			}).then(function(_armored)
5025
			{
5026
				self.et2.getWidgetById('mimeType').set_value(false);
5027
				self.et2.getWidgetById('mail_plaintext').set_disabled(false);
5028
				self.et2.getWidgetById('mail_plaintext').set_value(_armored);
5029
				self.et2._inst.submit(null,null,true);
5030
			}).catch(function(_err)
5031
			{
5032
				self.egw.message(_err.message, 'error');
5033
			});
5034
			return false;
5035
		}
5036
		this.et2._inst.submit(null,null,true);
5037
	},
5038
5039
	/**
5040
	 * This function runs before client submit (send) mail to server
5041
	 * and takes care of mail integration modules to popup entry selection
5042
	 * dialog to give user a choice to which entry of selected app the compose
5043
	 * should be integereated.
5044
	 * @param {int|boolean} _integIndex
5045
	 *
5046
	 * @returns {Boolean} return true if to_tracker is checked otherwise false
5047
	 */
5048
	compose_integrate_submit: function (_integIndex)
5049
	{
5050
		if (_integIndex == false) return false;
5051
		var index = _integIndex || 0;
5052
		var integApps = ['to_tracker', 'to_infolog', 'to_calendar'];
5053
		var subject = this.et2.getWidgetById('subject');
5054
		var toolbar = this.et2.getWidgetById('composeToolbar');
5055
		var to_integrate_ids = this.et2.getWidgetById('to_integrate_ids');
5056
		var integWidget= {};
5057
		var self = this;
5058
5059
		integWidget = this.et2.getWidgetById(integApps[index]);
5060
		if (toolbar.options.actions[integApps[index]] &&
5061
				typeof toolbar.options.actions[integApps[index]]['mail_import'] != 'undefined' &&
5062
				typeof toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'] != 'unefined')
5063
		{
5064
			var mail_import_hook = toolbar.options.actions[integApps[index]]['mail_import']['app_entry_method'];
5065
			if (integWidget.get_value() == 'on')
5066
			{
5067
				this.integrate_checkAppEntry(egw.lang('Select %1 entry',integApps[index]), integApps[index].substr(3), subject.get_value(), '', mail_import_hook , function (args){
5068
					var value = {};
5069
					value[integApps[index]] = args.entryid;
5070
					var oldValue = to_integrate_ids.get_value()[0];
5071
					to_integrate_ids.set_value(jQuery.extend(value,oldValue));
5072
					index = index<integApps.length? ++index:false;
5073
					self.compose_integrate_submit(index);
5074
				});
5075
				return true;
5076
			}
5077
		}
5078
		else if(index<integApps.length)
5079
		{
5080
			this.compose_integrate_submit(++index);
5081
		}
5082
		else
5083
		{
5084
			this.compose_submitAction(false);
5085
		}
5086
		return false;
5087
	},
5088
5089
	/**
5090
	 * Set the selected checkbox action
5091
	 *
5092
	 * @param {type} _action selected toolbar action with checkbox
5093
	 * @returns {undefined}
5094
	 */
5095
	compose_setToggle: function (_action)
5096
	{
5097
		var widget = this.et2.getWidgetById (_action.id);
5098
		if (widget && typeof _action.checkbox != 'undefined' && _action.checkbox)
5099
		{
5100
			widget.set_value(_action.checked?"on":"off");
5101
		}
5102
	},
5103
5104
	/**
5105
	 * Set the selected priority value
5106
	 * @param {type} _action selected action
5107
	 * @returns {undefined}
5108
	 */
5109
	compose_priorityChange: function (_action)
5110
	{
5111
		var widget = this.et2.getWidgetById ('priority');
5112
		if (widget)
5113
		{
5114
			widget.set_value(_action.id);
5115
		}
5116
	},
5117
5118
	/**
5119
	 * Triger relative widget via its toolbar identical action
5120
	 * @param {type} _action toolbar action
5121
	 */
5122
	compose_triggerWidget:function (_action)
5123
	{
5124
		var widget = this.et2.getWidgetById(_action.id);
5125
		if (widget)
5126
		{
5127
			switch(widget.id)
5128
			{
5129
				case 'uploadForCompose':
5130
					document.getElementById('mail-compose_uploadForCompose').click();
5131
					break;
5132
				default:
5133
					widget.click();
5134
			}
5135
		}
5136
	},
5137
5138
	/**
5139
	 * Save drafted compose as eml file into VFS
5140
	 * @param {type} _action action
5141
	 */
5142
	compose_saveDraft2fm: function (_action)
5143
	{
5144
		var content = this.et2.getArrayMgr('content').data;
5145
		var subject = this.et2.getWidgetById('subject');
5146
		var elem = {0:{id:"", subject:""}};
5147
		if (typeof content != 'undefined' && content.lastDrafted && subject)
5148
		{
5149
			elem[0].id = content.lastDrafted;
5150
			elem[0].subject = subject.get_value();
5151
			this.mail_save2fm(_action, elem);
5152
		}
5153
		else
5154
		{
5155
			et2_dialog.alert('You need to save the message as draft first before to be able to save it into VFS','Save to filemanager','info');
5156
		}
5157
	},
5158
5159
	/**
5160
	 * Folder Management, opens the folder magnt. dialog
5161
	 * with the selected acc_id from index tree
5162
	 *
5163
	 * @param {egw action object} _action actions
5164
	 * @param {object} _senders selected node
5165
	 */
5166
	folderManagement: function (_action,_senders)
5167
	{
5168
		var acc_id = parseInt(_senders[0].id);
5169
		this.egw.open_link('mail.mail_ui.folderManagement&acc_id='+acc_id, '_blank', '720x500');
5170
	},
5171
5172
	/**
5173
	 * Show ajax-loader when the autoloading get started
5174
	 *
5175
	 * @param {type} _id item id
5176
	 * @param {type} _widget tree widget
5177
	 * @returns {Boolean}
5178
	 */
5179
	folderMgmt_autoloadingStart: function(_id, _widget)
5180
	{
5181
		return this.subscription_autoloadingStart (_id, _widget);
5182
	},
5183
5184
	/**
5185
	 * Revert back the icon after autoloading is finished
5186
	 * @param {type} _id item id
5187
	 * @param {type} _widget tree widget
5188
	 * @returns {Boolean}
5189
	 */
5190
	folderMgmt_autoloadingEnd: function(_id, _widget)
5191
	{
5192
		return true;
5193
	},
5194
5195
	/**
5196
	 *
5197
	 * @param {type} _ids
5198
	 * @param {type} _widget
5199
	 * @returns {undefined}
5200
	 */
5201
	folderMgmt_onSelect: function(_ids, _widget)
5202
	{
5203
		// Flag to reset selected items
5204
		var resetSelection = false;
5205
5206
		var self = this;
5207
5208
		/**
5209
		 * helper function to multiselect range of nodes in same level
5210
		 *
5211
		 * @param {string} _a start node id
5212
		 * @param {string} _b end node id
5213
		 * @param {string} _branch totall node ids in the level
5214
		 */
5215
		var rangeSelector = function(_a,_b, _branch)
5216
		{
5217
			var branchItems = _branch.split(_widget.input.dlmtr);
5218
			var _aIndex = _widget.input.getIndexById(_a);
5219
			var _bIndex = _widget.input.getIndexById(_b);
5220
			if (_bIndex<_aIndex)
5221
			{
5222
				var tmpIndex = _aIndex;
5223
				_aIndex = _bIndex;
5224
				_bIndex = tmpIndex;
5225
			}
5226
			for(var i =_aIndex;i<=_bIndex;i++)
5227
			{
5228
				self.folderMgmt_setCheckbox(_widget, branchItems[i], !_widget.input.isItemChecked(branchItems[i]));
5229
			}
5230
		};
5231
5232
		// extract items ids
5233
		var itemIds = _ids.split(_widget.input.dlmtr);
5234
5235
		if(itemIds.length == 2) // there's a range selected
5236
		{
5237
			var branch = _widget.input.getSubItems(_widget.input.getParentId(itemIds[0]));
5238
			// Set range of selected/unselected
5239
			rangeSelector(itemIds[0], itemIds[1], branch);
5240
		}
5241
		else if(itemIds.length != 1)
5242
		{
5243
			resetSelection = true;
5244
		}
5245
5246
		if (resetSelection)
5247
		{
5248
			_widget.input._unselectItems();
5249
		}
5250
	},
5251
5252
	/**
5253
	 * Set enable/disable checkbox
5254
	 *
5255
	 * @param {object} _widget tree widget
5256
	 * @param {string} _itemId item tree id
5257
	 * @param {boolean} _stat - status to be set on checkbox true/false
5258
	 */
5259
	folderMgmt_setCheckbox: function (_widget, _itemId, _stat)
5260
	{
5261
		if (_widget)
5262
		{
5263
			_widget.input.setCheck(_itemId, _stat);
5264
			_widget.input.setSubChecked(_itemId,_stat);
5265
		}
5266
	},
5267
5268
	/**
5269
	 *
5270
	 * @param {type} _id
5271
	 * @param {type} _widget
5272
	 * @TODO: Implement onCheck handler in order to select or deselect subItems
5273
	 *	of a checked parent node
5274
	 */
5275
	folderMgmt_onCheck: function (_id, _widget)
5276
	{
5277
		var selected = _widget.input.getAllChecked();
5278
		if (selected && selected.split(_widget.input.dlmtr).length > 5)
5279
		{
5280
			egw.message(egw.lang('If you would like to select multiple folders in one action, you can hold ctrl key then select a folder as start range and another folder within a same level as end range, all folders in between will be selected or unselected based on their current status.'));
5281
		}
5282
	},
5283
5284
	/**
5285
	 * Detele button handler
5286
	 * triggers longTask dialog and send delete operation url
5287
	 *
5288
	 */
5289
	folderMgmt_deleteBtn: function ()
5290
	{
5291
		var tree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('tree');
5292
		var menuaction= 'mail.mail_ui.ajax_folderMgmt_delete';
5293
5294
		var callbackDialog = function(_btn)
5295
		{
5296
			egw.appName='mail';
5297
			if (_btn === et2_dialog.YES_BUTTON)
5298
			{
5299
				if (tree)
5300
				{
5301
					var selFolders = tree.input.getAllChecked();
5302
					if (selFolders)
5303
					{
5304
						var selFldArr = selFolders.split(tree.input.dlmtr);
5305
						var msg = egw.lang('Deleting %1 folders in progress ...', selFldArr.length);
5306
						et2_dialog.long_task(function(_val, _resp){
5307
							console.log(_val, _resp);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
5308
							if (_val && _resp.type !== 'error')
5309
							{
5310
								var stat = [];
5311
								var folderName = '';
5312
								for(var i=0;i<selFldArr.length;i++)
5313
								{
5314
									folderName = selFldArr[i].split('::');
5315
									stat[selFldArr[i]] = folderName[1];
5316
								}
5317
								// delete the item from index folderTree
5318
								egw.window.app.mail.mail_removeLeaf(stat);
5319
							}
5320
							else
5321
							{
5322
								// submit
5323
								etemplate2.getByApplication('mail')[0].widgetContainer._inst.submit();
5324
							}
5325
						}, msg, egw.lang('Deleting folders'), menuaction, selFldArr, 'mail');
5326
						return true;
5327
					}
5328
				}
5329
			}
5330
		};
5331
		et2_dialog.show_dialog(callbackDialog, this.egw.lang('Are you sure you want to delete all selected folders?'), this.egw.lang('Delete folder'), {},
5332
			et2_dialog.BUTTON_YES_NO, et2_dialog.WARNING_MESSAGE, undefined, egw);
5333
	},
5334
5335
	/**
5336
	 * Implement mobile view
5337
	 *
5338
	 * @param {type} _action
5339
	 * @param {type} _sender
5340
	 */
5341
	mobileView: function(_action, _sender)
5342
	{
5343
		// row id in nm
5344
		var id = _sender[0].id;
5345
5346
		var defaultActions= {
5347
			actions:['delete', 'forward','reply','flagged'], // default actions to display
5348
			check:function(_action){
5349
				for (var i=0;i<= this.actions.length;i++)
5350
				{
5351
					if (_action == this.actions[i]) return true;
5352
				}
5353
				return false;
5354
			}
5355
		};
5356
5357
		var content = {};
5358
		var self = this;
5359
5360
		if (id){
5361
			content = egw.dataGetUIDdata(id);
5362
			content.data['toolbar'] = this.et2.getArrayMgr('sel_options').getEntry('toolbar');
5363
			// Set default actions
5364
			for(var action in content.data['toolbar'])
5365
			{
5366
				content.data.toolbar[action]['toolbarDefault'] = defaultActions.check(action);
5367
			}
5368
			// update local storage with added toolbar actions
5369
			egw.dataStoreUID(id,content.data);
5370
		}
5371
5372
		this.viewEntry(_action, _sender, true, function(etemplate){
5373
			// et2 object in view
5374
			var et2 = etemplate.widgetContainer;
5375
			// iframe to load message
5376
			var iframe = et2.getWidgetById('iframe');
5377
			// toolbar widget
5378
			var toolbar = et2.getWidgetById('toolbar');
5379
			// attachments details title DOM node
5380
			var $attachment = jQuery('.attachments span.et2_details_title');
5381
			// details DOM
5382
			var $details = jQuery('.et2_details.details');
5383
			// Content
5384
			var content = et2.getArrayMgr('content').data;
5385
5386
			// set the current selected row
5387
			et2.mail_currentlyFocussed = id;
5388
5389
			if (content.attachmentsBlock.length>0 && content.attachmentsBlock[0].filename)
5390
			{
5391
				$attachment.text(self.egw.lang('%1 attachments', content.attachmentsBlock.length));
5392
			}
5393
			else
5394
			{
5395
				// disable attachments area if there's no attachments
5396
				$attachment.parent().hide();
5397
			}
5398
			// disable the detials if there's no details
5399
			if (!content.ccaddress && !content.additionaltoaddress) $details.hide();
5400
5401
			toolbar.set_actions(content.toolbar);
5402
			var toaddressdetails = self.et2_view.widgetContainer.getWidgetById('toaddressdetails');
5403
			if (toaddressdetails && content.additionaltoaddress)
5404
			{
5405
				toaddressdetails.set_value('... ' +content.additionaltoaddress.length + egw.lang(' more'));
5406
				jQuery(toaddressdetails.getDOMNode()).off().on('click', function(){
5407
					$details.find('.et2_details_toggle').click();
5408
				});
5409
			}
5410
5411
			// Request email body from server
5412
			iframe.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:id}));
5413
			jQuery(iframe.getDOMNode()).on('load',function(){
5414
5415
				if (jQuery(this.contentWindow.document.body).find('#calendar-meeting').length > 0)
5416
				{
5417
					var frame = this;
5418
					jQuery(this).show();
5419
					// calendar meeting mails still need to be in iframe, therefore, we calculate the height
5420
					// and set the iframe with a fixed height to be able to see all content without getting
5421
					// scrollbar becuase of scrolling issue in iframe
5422
					window.setTimeout(function(){jQuery(frame).height(frame.contentWindow.document.body.scrollHeight);}, 500);
5423
				}
5424
				else
5425
				{
5426
					// Use prepare print function to copy iframe content into div
5427
					// as we don't want to show content in iframe (scrolling problem).
5428
					self.mail_prepare_print(jQuery(this));
5429
				}
5430
5431
5432
			});
5433
		});
5434
	}
5435
});
5436